通过两个连接的M2M字段来订购Django查询集

时间:2014-01-21 14:06:08

标签: python django orm m2m

我有以下Django模型(这里大大简化):

class Author:
    name = models.TextField()

class Editor:
    name = model.TextField()

class Publication:
    authors = models.ManyToManyField(Author)
    editors = models.ManyToManyField(Editor)

出版物可以包含 作者编辑器,但不能同时具有两者。我想按照字母顺序对作者和编辑的统一进行出版物清单。换句话说,我想按虚拟字段排序,让我们称之为creators,这是作者和编辑的串联。

查询:

Publication.objects.all().order_by('authors__name', 'editors__name')

...会将没有作者的出版物聚集在一起,并且根据编辑对该组进行排序,这不是我想要的。实际上,它应该使用任何作者或编辑可用于出版物并按此排序。

这种排序必须在数据库级别进行,结果集可能很大。

3 个答案:

答案 0 :(得分:0)

一种方法是创建一个名为creators的方法:

class Publication:
    authors = models.ManyToManyField(Author)
    editors = models.ManyToManyField(Editor)

    def creators(self):
        return self.authors + self.creators

但缺点是你不能在数据库级别但在Python级别执行排序:

sorted(Publication.objects.all(), key=lambda k: " ".join(p.name for p in k))

答案 1 :(得分:0)

我可以把它扔出去吗?

您可能希望AuthorsEditors继承Contributors。因为这两个模型都有诸如姓名,地址等的东西。

答案 2 :(得分:0)

要按照定义了值的字段进行排序,您需要在模型级别,使用自定义聚合或使用附加子句的位置创建QuerySet可以访问的组合字段。

如果您不需要完全与数据库无关,那么额外可能是最容易实现的:

qs = Publication.objects.extra({
   select={'contributor': "COALESCE(author.name,editor.name)"}
})
qs.extra(order_by = ['contributor'])

https://docs.djangoproject.com/en/1.6/ref/models/querysets/#django.db.models.query.QuerySet.extra

如果确实需要独立于数据库,则应该使用concat的一个实现作为聚合。例如,

http://harkablog.com/inside-the-django-orm-aggregates.html