【问题标题】:Order Django queryset by two concatenated M2M fields通过两个连接的 M2M 字段订购 Django 查询集
【发布时间】:2014-02-11 04:20:12
【问题描述】:

我有以下 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')

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

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

【问题讨论】:

    标签: python django orm m2m


    【解决方案1】:

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

    【讨论】:

    • 结果集很大,所以这种排序必须在数据库级别发生。我已将此作为注释添加到我的问题中。 :)
    • 为什么不在保存时添加一个带有排序列表的附加列?在执行连接时,无论如何您都必须对名称进行排序。
    • M2M 字段还记得吗? M2M 关系列表可以在不调用 save() 的情况下更改。
    • 是的。但是您仍然可以使用 through 模型和信号 mentioned in this answer
    【解决方案2】:

    我可以把它扔出去吗?

    您可能希望AuthorsEditors 继承自Contributors。因为这两个模型都会有名字和姓氏、地址等内容。

    【讨论】:

    • 这是一个非常简单的例子。这种继承不会改变问题,只会在示例中添加不必要的额外行。
    • (话虽如此,实际上将两个字段合并为一个将是一种解决方案,但在这种情况下由于其他限制不适合。:)
    • 嗯。那么,您可以使用原始 sql 来完成。但这是最后的手段,不是吗。
    • 嗯,使用 .extra() 和 select 是我现在正在查看的连接两个已加入 M2M 值的列表。提示赞赏。 :)
    【解决方案3】:

    要按定义了值的任何字段进行排序,您需要在 QuerySet 可以访问的某个地方创建一个组合字段,无论是在模型级别,使用自定义聚合,还是使用额外的子句。

    如果您不需要完全与 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

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

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

    【讨论】:

    • 我希望能够使用您的 extra() 建议之类的东西,但我无法使其与我的 M2M 字段一起使用。请记住,每个出版物都可以有多个作者,编辑也是如此。有什么想法吗?
    猜你喜欢
    • 2013-03-25
    • 2012-01-18
    • 2020-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-05
    • 1970-01-01
    • 2022-11-01
    相关资源
    最近更新 更多