如果我有模型:
class A(Base):
a_id = Column(Integer, primary_key=True)
other = Column(Text)
name = Column(Text)
class B(Base):
b_id = Column(Integer, primary_key=True)
other = Column(Text)
class C(Base):
c_id = Column(Integer, primary_key=True)
b_id = Column(ForeignKey(B.b_id))
b = relationship(B)
name = Column(Text)
a = relationship(
A,
primaryjoin=and_(
A.name == foreign(name),
A.other == foreign(B.other)))
如何使关系
C.a
正常工作,以确保session.query(C).options(joinedload(C.a))
不会失败。在普通的SQL中,我会这样做:
select * from c
join b using(b_id)
join a on a.name = c.name and a.other = b.other
a.name, a.other
有一个唯一的约束,所以我知道每个a
都会得到1或0个c
。我想我需要以某种方式使用
secondary=
,但是我可以找到的所有示例都是纯多对多示例。谢谢!
最佳答案
您必须使用relationship to a non primary mapper来代替辅助,因为:
在一种复杂的连接情况下,即使(composite "secondary" join)技术也不够用;当我们试图从A
联接到B
时,使用之间的任意数量的C
,D
等,但是A
和B
之间也直接存在联接条件。在这种情况下,仅凭复杂的A
条件很难表达从B
到primaryjoin
的联接,因为中间表可能需要特殊处理,并且也不能用secondary
对象表示,因为A->secondary->B
模式不直接支持A
和B
之间的任何引用。
因此,按照文档中的示例,我们可以使用non primary mapper建立类之间的关系,该类将类A
映射到表a
和b
之间的联接:
from sqlalchemy import create_engine, Column, Integer, Text, ForeignKey, join, and_
from sqlalchemy.orm import relationship, mapper, sessionmaker, foreign
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('sqlite:///', echo=True)
Base = declarative_base()
Base.metadata.bind = engine
Session = sessionmaker()
class A(Base):
__tablename__ = 'a'
a_id = Column(Integer, primary_key=True)
other = Column(Text)
name = Column(Text)
class B(Base):
__tablename__ = 'b'
b_id = Column(Integer, primary_key=True)
other = Column(Text)
j = join(A, B, A.other == B.other)
A_viab = mapper(A, j, non_primary=True, properties={
"other": [j.c.a_other, j.c.b_other]
})
class C(Base):
__tablename__ = 'c'
c_id = Column(Integer, primary_key=True)
b_id = Column(ForeignKey(B.b_id))
b = relationship(B)
name = Column(Text)
a = relationship(
A_viab,
primaryjoin=and_(foreign(name) == A_viab.c.name,
b_id == A_viab.c.b_id))
并采取行动:
In [4]: session.add(A(name='name', other='other'))
In [5]: session.add(C(name='name', b=B(other='other')))
In [6]: session.commit()
...
In [7]: c = session.query(C).options(joinedload(C.a)).first()
2018-01-04 15:10:21,338 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2018-01-04 15:10:21,340 INFO sqlalchemy.engine.base.Engine SELECT c.c_id AS c_c_id, c.b_id AS c_b_id, c.name AS c_name, a_1.other AS a_1_other, b_1.other AS b_1_other, a_1.a_id AS a_1_a_id, a_1.name AS a_1_name, b_1.b_id AS b_1_b_id
FROM c LEFT OUTER JOIN (a AS a_1 JOIN b AS b_1 ON a_1.other = b_1.other) ON c.name = a_1.name AND c.b_id = b_1.b_id
LIMIT ? OFFSET ?
2018-01-04 15:10:21,340 INFO sqlalchemy.engine.base.Engine (1, 0)
In [8]: c.a
Out[8]: <cplxjoin.A at 0x7f0c81599630>
结果查询与您的手动SQL并不完全相同,但是aafic应该等效。
关于python - sqlalchemy关系与自身和父列的primaryjoin,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48080591/