SQLAlchemy рекурсивное отношение многие ко многим

У меня есть случай, когда я использую одну таблицу для хранения данных, связанных с пользователем и группой. Этот столбец называется профилем. Итак, в основном эта таблица представляет собой таблицу «многие ко многим» для случаев, когда один пользователь принадлежит ко многим группам или в одной группе много пользователей.

Я немного запутался, как это должно быть описано...

Вот упрощенное представление класса.

Модель отношений сущностей

модель

user_group_table = Table('user_group', metadata,
Column('user_id', Integer,ForeignKey('profiles.id',
    onupdate="CASCADE", ondelete="CASCADE")),
Column('group_id', Integer, ForeignKey('profiles.id',
    onupdate="CASCADE", ondelete="CASCADE"))
)

class Profile(Base)
  __tablename__ = 'profiles'

  id = Column(Integer, autoincrement=True, primary_key=True)
  name = Column(Unicode(16), unique=True) # This can be either user- / groupname
  groups = relationship('Profile', secondary=user_group_table, backref = 'users')
  users = relationship('Profile', secondary=user_group_table, backref = 'groups')

#Example of the usage:
user = Profile()
user.name = 'Peter'

salesGroup = Profile()
salesGroup.name = 'Sales'

user.groups.append(salesGroup)

salesGroup.users
>[peter]

person Heikki    schedule 30.06.2010    source источник
comment
Как правило, при использовании «многие ко многим» вам нужны 3 таблицы — по одной для каждого из двух сравниваемых объектов, а третья содержит записи, содержащие первичные ключи двух объектов, удовлетворяющих отношению. Тем не менее, я не уверен, что понял вопрос...   -  person Raven Dreamer    schedule 30.06.2010


Ответы (1)


Прежде всего, я согласен с комментарием Raven о том, что вы должны использовать отдельные таблицы для Users и Groups. Причина в том, что вы можете получить некоторые противоречивые данные, где User может иметь другие Users в качестве своих users отношений, а также у вас могут быть циклы в дереве отношений.

Сказав это, чтобы заставить отношения работать, объявите это следующим образом:

...
class Profile(Base):
    __tablename__ = 'profiles'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(Unicode(16), unique=True) # This can be either user- / groupname
    groups = relationship('Profile', 
                secondary=user_group_table,
                primaryjoin=user_group_table.c.user_id==id,
                secondaryjoin=user_group_table.c.group_id==id,
                backref='users')
...

См. также Указание альтернативных условий соединения для отношения(). раздел документации.

person van    schedule 01.07.2010
comment
Спасибо, Ван. Из-за типа программного обеспечения нам проще хранить все данные в одной таблице. Частью функциональности является то, что некоторые пользователи будут действовать как группа. Поначалу я тоже очень подозрительно относился к этой модели, но поскольку она сильно упрощает остальную часть программного обеспечения, я решил попробовать. - person Heikki; 01.07.2010
comment
Удачи с этим. Модель может быть простой, но вам необходимо обеспечить качество данных. - person van; 01.07.2010