Классы 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'

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

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

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

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

3 51

3 ответа:

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

base.py

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

а.ру

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")

б.ру

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"))

Си.ру

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

Я использую Python 2.7 + колба 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...

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

model/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')

model/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'))

model/__init__.py

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