按不同的反向FK对Django QuerySet进行排序

按不同的反向FK对Django QuerySet进行排序,django,many-to-many,django-queryset,Django,Many To Many,Django Queryset,使用ORM应该不会太难;使用原始SQL非常简单 我有一些模型: class Actor(models.Model): last_name = models.CharField(max_length=64) specialty = models.ManyToManyField(Specialty, blank=True) allergy = models.ManyToManyField(Allergy, blank=True) #.... TONS MORE M2M

使用ORM应该不会太难;使用原始SQL非常简单

我有一些模型:

class Actor(models.Model):
    last_name = models.CharField(max_length=64)
    specialty = models.ManyToManyField(Specialty, blank=True)
    allergy = models.ManyToManyField(Allergy, blank=True)
    #.... TONS MORE M2Ms HERE ....#

class Character(models.Model):
    actor = models.ForeignKey(Actor)
    name = models.CharField(max_length=64, null=True)
我相信这是正确的模式,因为一个演员扮演许多角色,但在大多数情况下,情况并非如此,例如:

m = Actor(last_name='Palin')
d = Character(actor=m, name='Dennis')
r = Character(actor=m, name='Right Head')
如果我想显示所有演员的列表,并获取他们所有的m2m关系,这很简单:

actors = Actor.objects.all().prefetch_related(specialty, allergy, ...)
根据用户输入,有一系列非常复杂的过滤器可应用于上述查询集,例如,演员对花生过敏但对污物不过敏

现在,如果我想得到相同的查询集,按不同的字符名排序,我知道的唯一方法是查询字符,选择相关的参与者,并预取相关的M2M

不幸的是,这将需要我重新编写所有过滤器。因为过敏症患者必须成为演员


答案是什么?如何以尽可能干燥的方式提供按角色排序和按角色排序?

如果您不想重新编写角色筛选器,使用角色QS约束角色筛选器如何?例如:

actors = Actor.objects.filter(allergy__name='peanuts')
chars = Character.objects.filter(actor__in=actors)
然后,你可以按你的意愿点chars

编辑:我想我知道你的问题了。您希望角色和其他和角色相关的记录一起预取。这是与select_相关的ex的一个很好的用例:

actors = Actor.objects.filter(allergy__name='peanuts').select_related('character_set').prefetch_related()
这将产生所有匹配的参与者,并在结果集中包含相关的角色记录,从而允许您对角色名称进行排序,而无需每次访问数据库。最后一次预回迁将带来所有M2M记录,假设您也需要这些记录

另一种编辑:从这里,有许多方法可以重新排序或重新组织结果数据。将其表示为具有预加载角色的角色记录的一种可能方法是:

from itertools import chain
by_chars = chain(*[a.character_set.all() for a in actors])
或者,如果更易于阅读/维护:

by_chars = []
for a in actors:
    for c in a.character_set.all():
        by_chars.append(c)

由于您已经预加载了所有内容,因此对结果集进行额外的排序和分组不需要对数据库进行任何额外的访问。

好的,这会起作用,但不会发生与预取相关的情况。在模板端将有大量的数据库活动。考虑3000个参与者和5-6000个字符。过滤不依赖于预取。请注意,我并没有返回Actor QS的结果,而是使用它来过滤角色。这只是一次访问数据库。一旦你完成了对角色的排序/筛选,你就可以应用。如果你的用例需要,预回迁是相关的。然后我如何显示所有角色,按角色名称排序。其中,在上面的例子中,“佩林”将有两个条目。这将导致许多查询。不完全是这样:如果我选择所有参与者,按参与者名称,我会得到一个。如果我按角色名称选择所有演员,我想要2个,但它将是相同的queryset。我需要返回,@RobL这只是检索到的数据的额外分组。增加了几种可能的方法。