SQLAlchemy отношения многие ко многим с общими ключами SHARED - PullRequest
0 голосов
/ 14 февраля 2020

Я создал отношение SQL-Alchemy «многие ко многим» с помощью составных первичных ключей. Поэтому также внешние ключи между тремя таблицами являются составными. Один из столбцов первичного ключа является общим. Это должно быть того же значения. Diagram of the three tables Кажется, что код, который я использовал, работает, но теперь я получаю предупреждения, которые говорят: отношение '.bs' скопирует столбец B.group в столбец A_B.group, который конфликтует с отношения: «A.bs» (копирует Ab в A_B.group). Рассмотрите возможность применения viewonly = True к отношениям «только для чтения» или предоставьте условие первичного соединения, помечающее записываемые столбцы аннотацией 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)

Я не могу установить отношение на viewonly. Как мне изменить мой код, чтобы он работал без предупреждения?

1 Ответ

0 голосов
/ 18 февраля 2020

В дополнение к , предоставляющему 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...