SQLAlchemy 链式关联代理用于曾孙吗?
我有四个类,分别是:Group
(组)、Parent
(父母)、Child
(孩子)和Toy
(玩具)。
Group
(组)有一个指向Parent
(父母)的关系。Parent
(父母)有一个指向Child
(孩子)的关系。Child
(孩子)有一个指向Toy
(玩具)的关系。
Parent
(父母)有一个叫做toys
的association_proxy
,可以获取所有Toy
(玩具),这些玩具是Parent
(父母)的孩子们拥有的。
我想要获取一个Group
(组)中的所有玩具。我尝试在Group
(组)上创建一个指向Parent
(父母)玩具的association_proxy
,但结果是这样的:
[[<Toy 1>, <Toy 2>], [], [], []]
而我想要的是:
[<Toy 1>, <Toy 2>]
如果Parent
(父母)的children
(孩子)没有任何Toy
(玩具),那么toys
的关联代理就会是[]
(空列表)。但是,第二个关联代理并不知道要排除这些空列表。而且,这些列表应该被合并。有没有办法让这个工作正常?
class Group(db.Model):
id = db.Column(db.Integer, primary_key=True)
created_at = db.Column(db.DateTime, default=utils.get_now_datetime)
name = db.Column(db.String(80, convert_unicode=True))
# relationships
parents = db.relationship('Parent', backref='group')
toys = association_proxy('parents', 'toys')
class Parent(db.Model):
id = db.Column(db.Integer, primary_key=True)
group_id = db.Column(db.Integer, db.ForeignKey('group.id', ondelete='CASCADE'))
created_at = db.Column(db.DateTime, default=utils.get_now_datetime)
first_name = db.Column(db.String(80, convert_unicode=True))
last_name = db.Column(db.String(80, convert_unicode=True))
children = db.relationship('Child', backref='parent', cascade='all, delete')
toys = association_proxy('children', 'toys')
class Child(db.Model):
id = db.Column(db.Integer, primary_key=True)
parent_id = db.Column(db.Integer, db.ForeignKey('parent.id', ondelete='CASCADE'))
created_at = db.Column(db.DateTime, default=utils.get_now_datetime)
class Toy(db.Model):
id = db.Column(db.Integer, primary_key=True)
child_id = db.Column(db.Integer, db.ForeignKey('child.id', ondelete='CASCADE'))
created_at = db.Column(db.DateTime, default=utils.get_now_datetime)
child = db.relationship('Child', backref=db.backref("toys",cascade="all, delete-orphan", order_by="desc(Toy.id)"))
1 个回答
9
既然这些只是用来获取和查看数据(就像你在评论中提到的,添加数据会让事情变得模糊),我更倾向于使用一个 viewonly
的关系,而不使用 association_proxy
:
class Group(db.Model):
# ...
toys = relationship('Toy',
secondary="join(Group, Parent, Group.id == Parent.group_id).join(Child, Parent.id == Child.parent_id)",
primaryjoin="and_(Group.id == Parent.group_id, Parent.id == Child.parent_id)",
secondaryjoin="Child.id == Toy.child_id",
viewonly=True,
)
请注意,这是 SQLAlchemy 的一个新特性,详细信息可以在文档的 复合“次级”连接
部分找到。
然后你可以仅仅用它来查询数据:
group_id = 123
group = session.query(Group).get(group_id)
print(group.toys)
或者你甚至可以用它来过滤数据,比如要找一个名字叫“超级马里奥”的玩具所在的组,你可以这样做:
group = session.query(Group).filter(Group.toys.any(Toy.name == "Super Mario"))
但实际上,你可以用简单的查询来完成所有这些,或者创建一个支持查询的属性。有关更多信息,请查看文档中的 自定义列属性 部分,在那里你可以使用任何简单的属性,column_property
或 hybrid attribute
。