Автоматически распространяющее удаление при использовании двунаправленной ассоциации_proxy

Я использую двунаправленную association_proxy для связывания свойств Group.members и User.groups . У меня проблемы с удалением члена из Group.members . В частности, Group.members.remove успешно удалит запись из Group.members , но оставит None вместо соответствующей записи в User.groups .

Более конкретно, следующий (минимально-ишевой) репрезентативный фрагмент кода не выполняет свое последнее утверждение:

 import sqlalchemy as sa from sqlalchemy.orm import Session from sqlalchemy.ext.associationproxy import association_proxy from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class Group(Base): __tablename__ = 'group' id = sa.Column(sa.Integer, autoincrement=True, primary_key=True) name = sa.Column(sa.UnicodeText()) members = association_proxy('group_memberships', 'user', creator=lambda user: GroupMembership(user=user)) class User(Base): __tablename__ = 'user' id = sa.Column(sa.Integer, autoincrement=True, primary_key=True) username = sa.Column(sa.UnicodeText()) groups = association_proxy('group_memberships', 'group', creator=lambda group: GroupMembership(group=group)) class GroupMembership(Base): __tablename__ = 'user_group' user_id = sa.Column(sa.Integer, sa.ForeignKey('user.id'), primary_key=True) group_id = sa.Column(sa.Integer, sa.ForeignKey('group.id'), primary_key=True) user = sa.orm.relationship( 'User', backref=sa.orm.backref('group_memberships', cascade="all, delete-orphan")) group = sa.orm.relationship( 'Group', backref=sa.orm.backref('group_memberships', cascade="all, delete-orphan"), order_by='Group.name') if __name__ == '__main__': engine = sa.create_engine('sqlite://') Base.metadata.create_all(engine) session = Session(engine) group = Group(name='group name') user = User(username='user name') group.members.append(user) session.add(group) session.add(user) session.flush() assert group.members == [user] assert user.groups == [group] group.members.remove(user) session.flush() assert group.members == [] assert user.groups == [] # This assertion fails, user.groups is [None] 

Я попытался следовать ответам на отношения SQLAlchemy с проблемами association_proxy и как SQLAlchemy association_proxy можно использовать в двух направлениях? но они, похоже, не помогают.

One Solution collect form web for “Автоматически распространяющее удаление при использовании двунаправленной ассоциации_proxy”

Я обнаружил вашу проблему почти полностью случайно, так как я пытался выяснить, что происходит.

Поскольку в db не было данных, я добавил session.commit() . Оказывается, что (из связанного ответа):

Эти изменения не сохраняются постоянно на диске или видимы для других транзакций, пока база данных не получит COMMIT для текущей транзакции (что и делает session.commit ()).

Поскольку вы просто .flush() процессе изменений, sqlalchemy никогда не запрашивает базу данных повторно. Вы можете проверить это, добавив:

 import logging logging.getLogger('sqlalchemy').setLevel(logging.INFO) logging.getLogger('sqlalchemy').addHandler(logging.StreamHandler()) 

А затем просто запустите свой код. Он отобразит все запросы, которые запускаются по мере их возникновения. Затем вы можете изменить session.flush() на session.commit() а затем повторно запустить, и вы увидите, что несколько SELECT запускаются после вашей commit .

Похоже, что session.expire(user) или session.refresh(user) также заставит обновить пользователя. Я не уверен, есть ли способ заставить обновление распространяться на другой объект, не будучи явно о нем (или если это даже желательно).

  • SQLAlchemy group_concat и дубликаты
  • Как вложить некоторые родительские поля объекта при сериализации объектов с использованием зефира
  • Легко конвертировать между столбцами SQLAlchemy и типами данных?
  • Использование DATEADD в sqlalchemy
  • Массовая вставка Pandas DataFrame с использованием SQLAlchemy
  • SQLAlchemy - интроспекция ORM-классов / объектов
  • SQLAlchemy: удаление каскада
  • Как использовать зефир для сериализации пользовательского поля sqlalchemy?
  • Python - лучший язык программирования в мире.