Mr *_*pha 6 python many-to-many sqlalchemy
我在SQLAlchemy的Flask应用程序中使用关联对象设置了多对多的关系.然后,我在类之间设置了关联代理,以提供更直接的访问,而不是通过关联对象.
以下是设置的缩写示例:
class Person(Model):
__tablename__ = 'persons'
id = Column(Integer, primary_key=True)
last_name = Column(Text, nullable=False)
groups = association_proxy('group_memberships', 'group')
# Other stuff
class Group(Model):
__tablename__ = 'groups'
id = Column(Integer, primary_key=True)
name = Column(Text, nullable=False)
members = association_proxy('group_memberships', 'person')
# Other stuff
class GroupMembership(Model):
__tablename__ = 'group_memberships'
id = Column(Integer, primary_key=True)
person_id = Column(Integer, ForeignKey('persons.id'), nullable=False)
group_id = Column(Integer, ForeignKey('groups.id'), nullable=False)
person = relationship('Person', uselist=False, backref=backref('group_memberships', cascade='all, delete-orphan'))
group = relationship('Group', uselist=False, backref=backref('group_memberships', cascade='all, delete-orphan'))
# Other stuff
Run Code Online (Sandbox Code Playgroud)
我不能为我的生活弄清楚如何让返回的成员group.members按他们排序last_name?
Ilj*_*ilä 11
为了排序,group.members您必须在加载GroupMembership关联对象时让人员可以进行排序.这可以通过连接来实现.
在当前配置中,group.members首先加载GroupMembership对象,填充group.group_memberships关系,然后在关联代理访问GroupMembership.person关系属性时为每个Person触发SELECT .
相反,您希望在同一查询中加载GroupMemberships和Persons,排序依据Person.last_name:
class GroupMembership(Model):
__tablename__ = 'group_memberships'
id = Column(Integer, primary_key=True)
person_id = Column(Integer, ForeignKey('persons.id'), nullable=False)
group_id = Column(Integer, ForeignKey('groups.id'), nullable=False)
person = relationship('Person',
backref=backref('group_memberships',
cascade='all, delete-orphan'),
lazy='joined', innerjoin=True,
order_by='Person.last_name')
group = relationship('Group', backref=backref('group_memberships',
cascade='all, delete-orphan'))
# Other stuff
Run Code Online (Sandbox Code Playgroud)
您需要order_by='Person.last_name'在标量关系属性上定义GroupMembership.person而不是backref Group.group_memberships,这看起来像是合乎逻辑的事情.另一方面,order_by"表示加载这些项时应该应用的顺序",因此在使用连接加载时是有意义的.由于您将加入多对一引用并且外键不可为空,因此您可以使用内部联接.
根据给定的定义:
In [5]: g = Group(name='The Group')
In [6]: session.add_all([GroupMembership(person=Person(last_name=str(i)), group=g)
...: for i in range(30, 20, -1)])
In [7]: session.commit()
In [8]: g.members
2017-06-29 09:17:37,652 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2017-06-29 09:17:37,653 INFO sqlalchemy.engine.base.Engine SELECT groups.id AS groups_id, groups.name AS groups_name
FROM groups
WHERE groups.id = ?
2017-06-29 09:17:37,653 INFO sqlalchemy.engine.base.Engine (1,)
2017-06-29 09:17:37,655 INFO sqlalchemy.engine.base.Engine SELECT group_memberships.id AS group_memberships_id, group_memberships.person_id AS group_memberships_person_id, group_memberships.group_id AS group_memberships_group_id, persons_1.id AS persons_1_id, persons_1.last_name AS persons_1_last_name
FROM group_memberships JOIN persons AS persons_1 ON persons_1.id = group_memberships.person_id
WHERE ? = group_memberships.group_id ORDER BY persons_1.last_name
2017-06-29 09:17:37,655 INFO sqlalchemy.engine.base.Engine (1,)
Out[8]: [<__main__.Person object at 0x7f8f014bdac8>, <__main__.Person object at 0x7f8f014bdba8>, <__main__.Person object at 0x7f8f014bdc88>, <__main__.Person object at 0x7f8f01ddc390>, <__main__.Person object at 0x7f8f01ddc048>, <__main__.Person object at 0x7f8f014bdd30>, <__main__.Person object at 0x7f8f014bde10>, <__main__.Person object at 0x7f8f014bdef0>, <__main__.Person object at 0x7f8f014bdfd0>, <__main__.Person object at 0x7f8f0143b0f0>]
In [9]: [p.last_name for p in _]
Out[9]: ['21', '22', '23', '24', '25', '26', '27', '28', '29', '30']
Run Code Online (Sandbox Code Playgroud)
此解决方案的缺点person是始终会急切地加载关系,并在查询GroupMemberships时应用ORDER BY:
In [11]: session.query(GroupMembership).all()
2017-06-29 12:33:28,578 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2017-06-29 12:33:28,578 INFO sqlalchemy.engine.base.Engine SELECT group_memberships.id AS group_memberships_id, group_memberships.person_id AS group_memberships_person_id, group_memberships.group_id AS group_memberships_group_id, persons_1.id AS persons_1_id, persons_1.last_name AS persons_1_last_name
FROM group_memberships JOIN persons AS persons_1 ON persons_1.id = group_memberships.person_id ORDER BY persons_1.last_name
2017-06-29 12:33:28,578 INFO sqlalchemy.engine.base.Engine ()
Out[11]:
...
Run Code Online (Sandbox Code Playgroud)
...除非明确使用其他加载策略:
In [16]: session.query(GroupMembership).options(lazyload('person')).all()
2018-04-05 21:10:52,404 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2018-04-05 21:10:52,405 INFO sqlalchemy.engine.base.Engine SELECT group_memberships.id AS group_memberships_id, group_memberships.person_id AS group_memberships_person_id, group_memberships.group_id AS group_memberships_group_id
FROM group_memberships
2018-04-05 21:10:52,405 INFO sqlalchemy.engine.base.Engine ()
Run Code Online (Sandbox Code Playgroud)
如果您不时需要备用订单,则必须恢复发出使用显式预先加载的完整查询并按以下顺序排序:
In [42]: g = session.query(Group).\
...: filter_by(id=1).\
...: join(GroupMembership).\
...: join(Person).\
...: options(contains_eager('group_memberships')
...: .contains_eager('person')).\
...: order_by(Person.last_name.desc()).\
...: one()
...:
In [43]: [m.last_name for m in g.members]
Out[43]: ['30', '29', '28', '27', '26', '25', '24', '23', '22', '21']
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1015 次 |
| 最近记录: |