我正在使用Flask-SQLAlchemy使用Association Objects和association_proxy
创建多对多关系,但我遇到了一个问题:当我使用association_proxy
时,我可以设置它,这样当我将一个新实例附加到关系的一侧时,将创建关联对象,但如果我尝试从关系的另一侧添加实例,则关联对象构造函数赢了传递正确的实例。
以下是一个简化示例,Club
有很多People
,People
有很多Club
,而关联对象是Membership
:
class Club(db.Model):
__tablename__ = 'clubs'
id = db.Column(db.Integer, db.Sequence('clubs_id_seq'), autoincrement=True, primary_key=True)
name = db.Column(db.String(255))
memberships = db.relationship('Membership', backref='club')
members = association_proxy('memberships', 'club') # Can I pass a Person instance to Membership here?
created_at = db.Column('created_at', db.DateTime, default=datetime.datetime.now())
def __init__(self, name):
self.name = name
class Person(db.Model):
__tablename__ = 'people'
id = db.Column(db.Integer, db.Sequence('people_id_seq'), autoincrement=True, primary_key=True)
name = db.Column(db.String(255))
memberships = db.relationship('Membership', backref='person')
clubs = association_proxy('memberships', 'club')
created_at = db.Column('created_at', db.DateTime, default=datetime.datetime.now())
def __init__(self, name):
self.name = name
class Membership(db.Model):
__tablename__ = 'memberships'
person_id = db.Column('person_id', db.Integer, db.ForeignKey('people.id'), primary_key=True)
club_id = db.Column('club_id', db.Integer, db.ForeignKey('clubs.id'), primary_key=True)
club = db.relationship('Club', backref='membership')
joined_at = db.Column('joined_at', db.DateTime, default=datetime.datetime.now())
def __init__(self, club):
self.club = club
我正在使用association_proxy
,因为Club
和Person
之间的联系不仅重要;我还希望能够在需要时检索joined_at
的{{1}}属性。但是,在大多数情况下,我只会查询并附加Membership
.members
或Club
.clubs
Person
。在此示例中,我可以通过调用Membership
来创建新的person_instance.clubs.append(club_instance)
,但由于Membership
的构造函数只能使用一个参数,如果我可以调用club_instance.members.append(person_instance)
是向后工作?我可能会迭代club_instance.members
似乎很蹩脚,但必须记住不要append()
。我错过了什么吗?
答案 0 :(得分:1)
在this Google Groups discussion找到我的答案。这是相关部分:
class DossierTarife(Base):
__tablename__ = 'tarifer_dossier'
IdDossier = Column(Integer, ForeignKey('dossier.IdDossier'), primary_key=True)
IdAt = Column(Integer, ForeignKey('article_tarife.IdAt'), primary_key=True)
dossier = relationship(Dossier, backref=backref("tarifer_dossier", cascade="all, delete-orphan"))
article_tarife = relationship(ArticleTarife, backref=backref("tarifer_dossier"))
class Dossier(Base):
__tablename__ = 'dossier'
IdDossier = Column('IdDossier', Integer, primary_key=True)
...
class ArticleTarife(Base):
__tablename__ = 'article_tarife'
IdAt = Column('IdAt', Integer, primary_key=True)
...
Dossier.LesTar = association_proxy("tarifer_dossier", "article_tarife", creator=lambda art:DossierTarife(article_tarife=art))
ArticleTarife.LesTar = association_proxy("tarifer_dossier", "dossier", creator=lambda dos:DossierTarife(dossier=dos))
我直接在课程定义中指定了我的association_proxy
,而不是在上述事实之后进行,而且也很有效。
同样非常有用的是this SO answer描述如何正确删除关联对象行:
user = relationship(User, backref=backref('user_to_groups', cascade='all, delete-orphan'))
group = relationship(Group, backref=backref('group_to_user', cascade='all, delete-orphan'))