覆盖 sqlalchemy 中的关系行为

2024-01-09

假设我以声明方式有三个表,Parent, Child, and Pet,以这样的方式

  • Parent与两者都有多对多关系Child and Pet
  • Child与 具有一对多关系Pet

它们的代码是(使用 Flask-SQLAlchemy,尽管我相信解决方案存在于 SQLAlchemy 领域而不是 Flask 中)。

class Parent(db.Model):
    __tablename__ = 'parents'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64))

    # many to many relationship between parent and children
    # my case allows for a children to have many parents. Don't ask.
    children = db.relationship('Child',
                           secondary=parents_children_relationship,
                           backref=db.backref('parents', lazy='dynamic'),
                           lazy='dynamic')

    # many to many relationship between parents and pets
    pets = db.relationship('Pet',
                             secondary=users_pets_relationship,
                             backref=db.backref('parents', lazy='dynamic'), #
                             lazy='dynamic')

# many to many relationship between parents and children
parents_children_relationship = db.Table('parents_children_relationship',
    db.Column('parent_id', db.Integer, db.ForeignKey('parents.id')),
    db.Column('child_id', db.Integer, db.ForeignKey('children.id')),
    UniqueConstraint('parent_id', 'child_id'))

# many to many relationship between User and Pet 
users_pets_relationship = db.Table('users_pets_relationship', 
    db.Column('parent_id', db.Integer, db.ForeignKey('parents.id')), 
    db.Column('pet_id', db.Integer, db.ForeignKey('pets.id')),
    UniqueConstraint('parent_id', 'pet_id'))

class Child(db.Model):
    __tablename__ = 'children'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64))
    # parents = <backref relationship with User model>

    # one to many relationship with pets
    pets = db.relationship('Pet', backref='child', lazy='dynamic')


class Pet(db.Model):
    __tablename__ = 'pets'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64))
    # child = backref relationship with cities
    child_id = db.Column(db.Integer, db.ForeignKey('children.id'), nullable=True)
    # parents = <relationship backref from User>

我想做这样的事情

parent_a = Parent()    
child_a = Child()
pet_a = Pet()

然后我可以这样做

parent_a.children.append(child_a)
# commit/persist data
parent_a.children.all() # [child_a]

我想实现这样的目标

child_a.pets.append(pet_a)
parent_a.children.append(child_a)
# commit/persist data
parent_a.children.all() # [child_a]
parent_a.pets.all() # [pet_a], because pet_a gets 
                    # automatically added to parent using some sorcery
                    # like for child in parent_a.children.all():
                    #     parent.pets.append(child.pets.all())
                    # or something like that.

我可以通过以下方法实现这一点Parent类似物体add_child_and_its_pets(),但我想重写关系的工作方式,所以我不需要重写可能受益于这种行为的其他模块,例如Flask-Admin例如。

基本上我应该如何覆盖backref.append方法或relationship.append方法还可以在调用时附加来自其他关系的其他对象,即在 python 端?我应该如何覆盖remove方法也一样?


For parent.pets.all(),我认为你可以用孩子作为二次连接 http://docs.sqlalchemy.org/en/latest/orm/join_conditions.html#composite-secondary-joins条件,并将其视为关联实体或联结表 https://en.wikipedia.org/wiki/Associative_entity.

这取决于您的表,但这看起来像:

Parent.pets = relationship(
    Pet,
    backref='parent'
    primaryjoin=Pet.child_id == Child.id,
    secondaryjoin=Child.parent_id == Parent.id
)

你也可以相当合理地做一个反向引用parent如果您选择 - 这将让您访问两者parent_a.petspet_a.parent.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

覆盖 sqlalchemy 中的关系行为 的相关文章

随机推荐