Подтвердить что ты не робот

Классы SQLAlchemy для файлов

Я пытаюсь выяснить, как распределять классы SQLAlchemy по нескольким файлам, и я могу в своей жизни не понять, как это сделать. Я новичок в SQLAlchemy, поэтому простите меня, если этот вопрос тривиален.

Рассмотрим эти 3 класса в каждом из своих файлов:

A.py:

from sqlalchemy import *
from main import Base

class A(Base):
    __tablename__ = "A"
    id  = Column(Integer, primary_key=True)
    Bs  = relationship("B", backref="A.id")
    Cs  = relationship("C", backref="A.id")

B.py:

from sqlalchemy import *
from main import Base

class B(Base):
    __tablename__ = "B"
    id    = Column(Integer, primary_key=True)
    A_id  = Column(Integer, ForeignKey("A.id"))

C.py:

from sqlalchemy import *
from main import Base

class C(Base):
    __tablename__ = "C"    
    id    = Column(Integer, primary_key=True)
    A_id  = Column(Integer, ForeignKey("A.id"))

А затем скажем, что у нас есть main.py что-то вроде этого:

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, backref, sessionmaker

Base = declarative_base()

import A
import B
import C

engine = create_engine("sqlite:///test.db")
Base.metadata.create_all(engine, checkfirst=True)
Session = sessionmaker(bind=engine)
session = Session()

a  = A.A()
b1 = B.B()
b2 = B.B()
c1 = C.C()
c2 = C.C()

a.Bs.append(b1)
a.Bs.append(b2)    
a.Cs.append(c1)
a.Cs.append(c2)    
session.add(a)
session.commit()

Вышеприведенная ошибка:

sqlalchemy.exc.NoReferencedTableError: Foreign key assocated with column 'C.A_id' could not find table 'A' with which to generate a foreign key to target column 'id'

Как я могу предоставить декларативную базу в этих файлах?

Каков "правильный" способ сделать это, учитывая, что я мог бы добавить что-то вроде Pylons или Turbogears поверх этого?

изменить 10-03-2011

Я нашел это описание из структуры Pyramids, которая описывает проблему и, что более важно, проверяет, что это актуальная проблема, а не (только) просто мое запутанное я, что проблема. Надеюсь, это поможет другим, кто осмеливается на эту опасную дорогу:)

4b9b3361

Ответ 1

Простейшим решением вашей проблемы будет вывести Base из модуля, который импортирует A, B и C; Перерыв циклического импорта.

base.py

from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()

a.py

from sqlalchemy import *
from base import Base
from sqlalchemy.orm import relationship

class A(Base):
    __tablename__ = "A"
    id  = Column(Integer, primary_key=True)
    Bs  = relationship("B", backref="A.id")
    Cs  = relationship("C", backref="A.id")

b.py

from sqlalchemy import *
from base import Base

class B(Base):
    __tablename__ = "B"
    id    = Column(Integer, primary_key=True)
    A_id  = Column(Integer, ForeignKey("A.id"))

c.py

from sqlalchemy import *
from base import Base

class C(Base):
    __tablename__ = "C"    
    id    = Column(Integer, primary_key=True)
    A_id  = Column(Integer, ForeignKey("A.id"))

main.py

from sqlalchemy import create_engine
from sqlalchemy.orm import relationship, backref, sessionmaker

import base


import a
import b
import c

engine = create_engine("sqlite:///:memory:")
base.Base.metadata.create_all(engine, checkfirst=True)
Session = sessionmaker(bind=engine)
session = Session()

a1 = a.A()
b1 = b.B()
b2 = b.B()
c1 = c.C()
c2 = c.C()

a1.Bs.append(b1)
a1.Bs.append(b2)    
a1.Cs.append(c1)
a1.Cs.append(c2)    
session.add(a1)
session.commit()

Работает на моей машине:

$ python main.py ; echo $?
0

Ответ 2

Я использую Python 2.7 + Flask 0.10 + SQLAlchemy 1.0.8 + Postgres 9.4.4.1

Этот шаблонный шаблон настроен на модели User и UserDetail, хранящиеся в том же файле "models.py" в модуле "пользователь". Эти классы наследуются от базового класса SQLAlchemy.

Все дополнительные классы, которые я добавил в мой проект, также были получены из этого базового класса, а по мере увеличения файла models.py я решил разбить файл models.py на один файл для каждого класса и столкнулся с ним описанная здесь проблема.

Решение, которое я нашел в тех же строках, что и сообщение @computermacgyver от 23 октября 2013 года, должно было включать все мои классы в файл init.py нового модуля, который я создал, чтобы провести все новые созданных файлов классов. Выглядит так:

/project/models/

__init__.py contains

from project.models.a import A 
from project.models.b import B
etc...

Ответ 3

Если я могу добавить свой смысл, так как у меня была такая же проблема. Вам нужно импортировать классы в файл, где вы создаете Base = declarative_base() ПОСЛЕ того, как вы создали Base и Tables. Краткое описание того, как настроен мой проект:

модель /user.py

from sqlalchemy import *
from sqlalchemy.orm import relationship

from model import Base

class User(Base):
     __tablename__ = 'user'

    id = Column(Integer, primary_key=True)
    budgets = relationship('Budget')

модель /budget.py

from sqlalchemy import *

from model import Base

class Budget(Base):
    __tablename__ = 'budget'

    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey('user.id'))

модель /__ __ INIT. Ру

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

_DB_URI = 'sqlite:///:memory:'
engine = create_engine(_DB_URI)

Base = declarative_base()
Base.metadata.create_all(engine)
DBSession = sessionmaker(bind=engine)
session = DBSession()

from .user import User
from .budget import Budget

Ответ 4

Для меня было достаточно добавить import app.tool.tool_entity внутри app.py и from app.tool.tool_entity import Tool внутри tool/__init__.py, чтобы создать таблицу. Я еще не пробовал добавлять отношения.

Структура папок:

app/
  app.py
  tool/
    __init__.py
    tool_entity.py
    tool_routes.py
# app/tool/tool_entity.py

from app.base import Base
from sqlalchemy import Column, Integer, String


class Tool(Base):
    __tablename__ = 'tool'

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False)
    fullname = Column(String)
    fullname2 = Column(String)
    nickname = Column(String)

    def __repr__(self):
        return "<User(name='%s', fullname='%s', nickname='%s')>" % (
            self.name, self.fullname, self.nickname)
# app/tool/__init__.py
from app.tool.tool_entity import Tool
# app/app.py

from flask import Flask
from sqlalchemy import create_engine
from app.tool.tool_routes import tool_blueprint
from app.base import Base


db_dialect = 'postgresql'
db_user = 'postgres'
db_pwd = 'postgrespwd'
db_host = 'db'
db_name = 'db_name'
engine = create_engine(f'{db_dialect}://{db_user}:{db_pwd}@{db_host}/{db_name}', echo=True)
Base.metadata.create_all(engine)


app = Flask(__name__)
@app.route('/')
def hello_world():
    return 'hello world'


app.register_blueprint(tool_blueprint, url_prefix='/tool')

if __name__ == '__main__':
    # you can add this import here, or anywhere else in the file, as debug (watch mode) is on, 
    # the table should be created as soon as you save this file.
    import app.tool.tool_entity
    app.run(host='0.0.0.0', port=5000, debug=True)