订购Django的查询集由两个串联的M2M领域

问题描述:

我有以下的Django模型(这里大大简化):订购Django的查询集由两个串联的M2M领域

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') 

...将聚集在一起是没有作者,并在该组中的排序按编辑出版物,这不是我想要的。实际上,它应该使用任何作者或编辑可用于发布和排序。

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

一种方法是创建一个名为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)) 
+0

结果集很大,所以这个排序必须发生在数据库级别。我已经添加了这个作为我的问题的一个笔记。 :) –

+0

为什么不在保存时添加一个具有排序列表名称的附加列?无论如何,您必须在执行连接时对名称进行排序。 – arocks

+0

M2M领域记得吗?无需调用save(),M2M关系列表就可以更改。 –

我可以把这个扔掉?您可能需要AuthorsEditors继承Contributors。因为这两个模型都有类似姓名,地址等。

+0

这是一个严格简化的例子。这种继承不会改变这个问题,只会为示例添加不必要的额外行。 –

+0

(也就是说,实际上将两个字段合并为一个将是一个解决方案,但在这种情况下由于其他限制而不适合。:) –

+0

嗯。然后你可以用原始的sql来完成。但这是最后的手段,不是。 –

要按字段中定义的值进行排序,您需要创建一个组合字段,可以在模型级别访问QuerySet ,使用自定义的Aggregate或使用额外的子句。

如果你不需要是完全不可知的DB额外的可能是最容易实现的:

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

如果您确实需要DB独立的,你应该看看使用一个concat作为聚合的实现。例如,

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

+0

我希望能够使用类似'extra()'的建议,但我无法使其与我的M2M领域一起工作。请记住,每个出版物可能有多位作者,编辑也是如此。有任何想法吗? –