Классы 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, которая описывает проблему и, что более важно, проверяет, что это актуальная проблема, а не (только) просто мое запутанное я, что проблема. Надеюсь, это поможет другим, кто осмеливается на эту опасную дорогу:)
Ответы
Ответ 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)