Django:按多对多字段订购模型
Posted
技术标签:
【中文标题】Django:按多对多字段订购模型【英文标题】:Django: Order a model by a many-to-many field 【发布时间】:2010-10-30 09:43:01 【问题描述】:我正在编写一个带有 People 模型的 Django 应用程序,但我遇到了障碍。我正在使用多对多关系将角色对象分配给人们 - 其中角色具有名称和权重。我希望按照最重角色的权重来排列我的人员名单。如果我执行 People.objects.order_by('-roles__weight'),那么当人们分配有多个角色时,我会得到重复。
我最初的想法是添加一个名为 heaviest-role-weight 的非规范化字段 - 并按此排序。然后可以在每次向用户添加或删除新角色时更新此信息。然而,事实证明,每次在 Django 中更新 ManyToManyField 时,都无法执行自定义操作(无论如何,yet)。
所以,我认为我可以完全过火并编写一个自定义字段、描述符和管理器来处理这个问题 - 但是当为 ManyToManyField 动态创建 ManyRelatedManager 时,这似乎非常困难。
我一直在尝试想出一些可以为我做这件事的聪明的 SQL - 我确信可以使用子查询(或几个),但我担心它不兼容所有Django 支持的数据库后端。
以前有没有人这样做过 - 或者对如何实现有任何想法?
【问题讨论】:
【参考方案1】:Django 1.1(当前为测试版)添加了aggregation 支持。您的查询可以通过以下方式完成:
from django.db.models import Max
People.objects.annotate(max_weight=Max('roles__weight')).order_by('-max_weight')
这会按最重的角色对人员进行排序,而不返回重复项。
生成的查询是:
SELECT people.id, people.name, MAX(role.weight) AS max_weight
FROM people LEFT OUTER JOIN people_roles ON (people.id = people_roles.people_id)
LEFT OUTER JOIN role ON (people_roles.role_id = role.id)
GROUP BY people.id, people.name
ORDER BY max_weight DESC
【讨论】:
【参考方案2】:这是一种无需注释的方法:
class Role(models.Model):
pass
class PersonRole(models.Model):
weight = models.IntegerField()
person = models.ForeignKey('Person')
role = models.ForeignKey(Role)
class Meta:
# if you have an inline configured in the admin, this will
# make the roles order properly
ordering = ['weight']
class Person(models.Model):
roles = models.ManyToManyField('Role', through='PersonRole')
def ordered_roles(self):
"Return a properly ordered set of roles"
return self.roles.all().order_by('personrole__weight')
这让你可以这样说:
>>> person = Person.objects.get(id=1)
>>> roles = person.ordered_roles()
【讨论】:
【参考方案3】:在 SQL 中是这样的:
select p.*, max (r.Weight) as HeaviestWeight
from persons p
inner join RolePersons rp on p.id = rp.PersonID
innerjoin Roles r on rp.RoleID = r.id
group by p.*
order by HeaviestWeight desc
注意:您的 SQL 方言可能不允许按 p.* 分组。如果是这样,只需列出表 p 中您打算在 select 子句中使用的所有列。
注意:如果您只是按 p.ID 分组,您将无法在 select 子句中调用 p 中的其他列。
我不知道这如何与 Django 交互。
【讨论】:
以上是关于Django:按多对多字段订购模型的主要内容,如果未能解决你的问题,请参考以下文章