Django:通过多对多字段订购模型

Rob*_*ing 12 sql django database-design django-models

我正在编写一个Django应用程序,它有一个People模型,我遇到了障碍.我正在为使用多对多关系的人分配角色对象 - 其中角色具有名称和权重.我希望按照他们最重要的角色来命令我的人员名单.如果我做People.objects.order_by(' - roles__weight'),那么当人们分配了多个角色时,我会得到重复.

我最初的想法是添加一个称为最重角色权重的非规范化字段- 并按此排序.每次添加或从用户删除新角色时,都可以更新此信息.然而,事实证明,有没有办法来执行自定义操作每次ManyToManyField是在Django(更新时间还没有,反正).

所以,我认为我可以完全超越并编写一个自定义字段,描述符和管理器来处理这个问题 - 但是当为ManyToManyField动态创建ManyRelatedManager时,这似乎非常困难.

我一直试图想出一些聪明的SQL,可以为我做这个 - 我敢肯定它可能有一个子查询(或几个),但我担心它不兼容将所有的数据库后端Django支持.

有没有人之前做过这个 - 或者有任何想法如何实现它?

Aym*_*ieh 13

Django 1.1(目前是测试版)增加了聚合支持.您的查询可以通过以下方式完成:

from django.db.models import Max
People.objects.annotate(max_weight=Max('roles__weight')).order_by('-max_weight')
Run Code Online (Sandbox Code Playgroud)

这会按照最重要的角色对人进行排序,而不会返回重复项.

生成的查询是:

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
Run Code Online (Sandbox Code Playgroud)


Set*_*eth 6

这是一种没有注释的方法:

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')
Run Code Online (Sandbox Code Playgroud)

这可以让你说:

>>> person = Person.objects.get(id=1)
>>> roles = person.ordered_roles()
Run Code Online (Sandbox Code Playgroud)