在SQLAlchemy ORM中使用二级连接
我正在尝试建立一个多对多的关系,这个关系是通过一个中间表连接三个表。具体来说,我有两个文件,一个是用来定义模型的(model.py),另一个是用来定义架构的(schema.py)。它们的内容如下:
model.py
import schema
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import *
class AbstractBase(object):
def __repr__(self):
macros = ["%s=%s" % (key, getattr(self, key, None)) for key in self.__table__.columns.keys()]
rep = "<%s(%s)>" % (self.__class__.__name__, str.join(', ', macros))
return rep
Base = declarative_base(cls=AbstractBase)
class A(Base):
__table__ = schema.a_table
dees = relationship("D",
secondary=schema.b_table,
primaryjoin="A.a_id==b_table.c.a_id",
secondaryjoin="b_table.c.c_id==D.d_id")
cees = relationship("C",
secondary=schema.b_table,
primaryjoin="A.a_id==schema.b_table.c.a_id",
secondaryjoin="b_table.c.d_id==C.c_id",
backref="a_collection")
class C(Base):
__table__ = schema.c_table
class D(Base):
__table__ = schema.d_table
schema.py
from sqlalchemy import *
from sqlalchemy.dialects.mysql import *
metadata = MetaData()
a_table = Table(
'a',
metadata,
Column("a_id", INTEGER(), primary_key=True, nullable=False),
Column("date", DATETIME(timezone=True)),
)
b_table = Table(
'shipment_runs',
metadata,
Column("a_id", ForeignKey("a.a_id"), primary_key=True,),
Column("c_id", ForeignKey("c.c_id"), primary_key=True),
Column("d_id", ForeignKey("d.d_id")),
)
c_table = Table(
'c',
metadata,
Column('c_id', INTEGER(), primary_key=True, nullable=False),
Column('name', VARCHAR(64), unique=True),
)
d_table = Table(
'd',
metadata,
Column('d_id', INTEGER(), primary_key=True, nullable=False)
)
不过,当我尝试创建这个关系时,出现了一个错误:
sqlalchemy.exc.InvalidRequestError: 在初始化映射器 Mapper|A|a 时,表达式 'A.a_id==b_table.c.a_id' 找不到名称(“name 'b_table' is not defined”)。如果这是一个类名,请考虑在定义完所有相关类后再将这个关系添加到类中。
请问有没有办法让我更改导入的内容,或者让映射器知道架构模块中的对象呢?
2 个回答
1
一般来说,你可以在字符串中使用表的名字,或者直接用实际的引用,不用字符串。
primaryjoin="A.a_id==shipment_runs.c.a_id",
primaryjoin=schema.a_table.c.a_id==schema.b_table.c.a_id,
不过,既然你在表里设置了ForeignKey
,SQLAlchemy聪明得很,简单的关系你甚至不需要用到连接,只要用secondary
就可以了。
c_list = relationship("C", secondary=schema.b_table, backref="a_list")
(我觉得你例子里的"C"和"D"是不是搞错了?)
4
我通过以下方式解决了这个问题:
class B(Base):
__table__ = schema.b_table
class A(Base):
__table__ = schema.a_table
dees = relationship("D",
secondary=b.__table__,
primaryjoin="A.a_id==B.a_id",
secondaryjoin="B.c_id==D.d_id")
cees = relationship("C",
secondary=B.__table__,
primaryjoin="A.a_id==B.a_id",
secondaryjoin="B.d_id==C.c_id",
backref="a_collection")
所有的功劳都要归功于这个问题: