【问题标题】:SQLAlchemy many-to-many relationship with SHARED composite keysSQLAlchemy 与 SHARED 复合键的多对多关系
【发布时间】:2020-05-30 01:04:53
【问题描述】:

我使用复合主键创建了一个 SQLAlchemy 多对多关系。因此,三个表之间的外键也是复合的。其中一个主键列是共享的。它必须具有相同的值。 我使用的代码似乎有效,但是我现在确实收到警告说:relationship 'A.bs' will copy column B.group to column A_B.group,这与关系冲突:'A.bs '(将 Ab 复制到 A_B.group)。考虑将 viewonly=True 应用于只读关系,或提供一个primaryjoin 条件,使用foreign() 注释标记可写列。

class A(Model):
  group = Column(Int, primary_key=True)
  id = Column(Int, primary_key=True)
  bs = relationship('B', secondary=Table('A_B',
    Column('group', Int, primary_key=True),
    Column('a', Int, primary_key=True),
    Column('b', Int, primary_key=True),
    ForeignKeyConstraint(['group', 'a'], ['A.group', 'A.id']),
    ForeignKeyConstraint(['group', 'b'], ['B.group', 'B.id'])
  ))

class B(Model):
  group = Column(Int, primary_key=True)
  id = Column(Int, primary_key=True)

我无法将关系设置为仅查看。如何修改我的代码以使其在没有警告的情况下工作?

【问题讨论】:

  • 所以无法解决警告并仍然使用“次要”参数? “重复”解决方案使用了一个有问题的附加表。
  • 我不明白为什么你不能使用辅助,你只需要通知 SQLA 它可以根据关系修改或不能修改什么,并传递一个明确的primaryjoinsecondaryjoin with annotations 是一种方法。也许这与一对多的情况有很大的不同,以至于副本没有足够清楚地覆盖它。

标签: python sql postgresql sqlalchemy


【解决方案1】:

除了providing the 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 关联。

【讨论】:

  • 好的,谢谢你的代码。我想这个解决方案也不是一个很好的选择,因为这些意想不到的事情正在发生。尝试使用错误的组附加元素时应该会出错。
  • 使用validator / events 可能是可行的。
猜你喜欢
  • 2013-02-21
  • 1970-01-01
  • 2012-06-14
  • 1970-01-01
  • 2015-12-13
  • 1970-01-01
  • 1970-01-01
  • 2018-05-30
  • 2021-10-10
相关资源
最近更新 更多