В дополнение к , предоставляющему primaryjoin
аннотации, как в сообщении об ошибке, вы должны предоставить secondaryjoin
при создании связи «многие ко многим» через вторичную таблицу:
a_b = Table('A_B',
Column('group', Integer, primary_key=True),
Column('a', Integer, primary_key=True),
Column('b', Integer, primary_key=True),
ForeignKeyConstraint(['group', 'a'], ['a.group', 'a.id']),
ForeignKeyConstraint(['group', 'b'], ['b.group', 'b.id'])
)
class A(Model):
group = Column(Integer, primary_key=True)
id = Column(Integer, primary_key=True)
bs = relationship(
'B', secondary=a_b,
primaryjoin='and_(A.group == foreign(A_B.c.group), A.id == foreign(A_B.c.a))',
secondaryjoin='and_(B.group == A_B.c.group, B.id == foreign(A_B.c.b))')
class B(Model):
group = Column(Integer, primary_key=True)
id = Column(Integer, primary_key=True)
A_B.c.group
не аннотируется как foreign()
во вторичном соединении, поэтому SQLAlchemy не копирует его дважды. Недостатком этого является то, что можно делать неожиданные вещи, такие как:
In [4]: a1 = A(group=1, id=1)
In [5]: a2 = A(group=2, id=1)
In [6]: session.add_all([a1, a2])
In [7]: b_oops = B(group=1, id=2)
In [8]: session.add(b_oops)
In [9]: a1.bs = [B(group=1, id=1), B(group=2, id=2)]
In [10]: session.commit()
In [11]: b_oops in a1.bs
Out[11]: True
Таким образом, B(group=2, id=2)
вставляется в базу данных, но вместо этого b_oops
связывается с a1
.