【问题标题】:Django: Order by evaluation of whether or not a date is emptyDjango:通过评估日期是否为空来排序
【发布时间】:2016-09-20 18:46:31
【问题描述】:

在 Django 中,是否可以根据字段是否为 None 来排序,而不是根据字段本身的值来排序?

我知道我可以将 QuerySet 发送到 python sorted(),但我想将其保留为 QuerySet 以供后续过滤。所以,我更喜欢在 QuerySet 本身中订购。

例如,我有一个终止日期字段,我想先对没有终止日期的字段进行排序,然后我想按不同的字段排序,例如姓氏、名字。

这可能吗,还是我坚持使用sorted(),然后必须使用包含的 id 执行一个全新的查询并在新的 QuerySet 上运行 sorted()?我可以这样做,但不希望浪费开销并使用 QuerySet 的优点,它们在评估之前不会运行。

翻译,假设我的应用程序是employee,我的模型是Employee,并且它具有三个字段“first_name (varchar)”、“last_name (varchar)”和“termination_date”,我该如何从 Django 获取此 SQL(日期)':

SELECT
    "employee_employee"."last_name",
    "employee_employee"."first_name",
    "employee_employee"."termination_date"

FROM "employee_employee"

ORDER BY
    "employee_employee"."termination_date" IS NOT NULL,
    "employee_employee"."last_name",
    "employee_employee"."first_name"

【问题讨论】:

    标签: python django


    【解决方案1】:

    Spectras 的答案工作正常,但它仅按“是否为空”对您的记录进行排序。有一种更短的方法可以让您在日期排序中随意放置空日期 - Coalesce

    from django.db.models import Value
    from django.db.models.functions import Coalesce
    
    wayback = datetime(year=1, month=1, day=1)  # or whatever date you want
    MyModel.objects
           .annotate(null_date=Coalesce('date_field', Value(wayback)))
           .order_by('null_date')
    

    这实际上将按字段'date_field' 排序,所有带有date_field == None 的记录将按照日期为wayback 的顺序排列。这与 PostgreSQL 完美配合,但可能需要在 MySQL 中进行一些原始 sql 转换,如 documentation 中所述。

    【讨论】:

    • 感谢您的回答,@schwobaseggl!我之前也没听说过Coalesce。它也必须是一个相对较新的添加。您知道Coalesce 或使用@spectras 提到的Case 语句是否具有资源优势?
    • 在 1.8 中添加。看来,两者非常相似:stackoverflow.com/questions/15523000/…。您可以使用str(queryset.query) 检查生成的 SQL,它们差别不大。 Coalesce 基本上是一条捷径。
    【解决方案2】:

    您应该可以通过query expressions 订购,如下所示:

    from django.db.models import IntegerField, Case, Value, When
    
    MyModel.objects.all().order_by(
        Case(
            When(some_field=None, then=Value(1)),
            default=Value(0),
            output_field=IntegerField(),
        ).asc(),
        'some_other_field'
    )
    

    我无法在这里进行测试,因此可能需要稍微摆弄一下,但这应该将具有some_field 的行放在具有some_field 的行之后。并且每组行都应该按some_other_field排序。

    当然,CASE/WHEN 比您在问题中提出的要麻烦一些,但我不知道如何让 Django ORM 输出它。也许其他人会有更好的答案。

    【讨论】:

    • 太棒了,我已经使用 Django 多年,但从未遇到过 Case 类。非常感谢,完美运行!
    • @Furbeenator> 这是一个相当新的添加。我认为 Django 1.7,甚至可能是 1.8。 djangoproject 团队正试图通过使用可组合的查询表达式使 Django ORM 更具表现力来杀死 .extra() 方法。更好的封装性和可移植性。
    • 这是有道理的,我不得不承认,我从 1.3 开始就一直在维护 Django,并且还没有查看最新的两个发行说明以了解所有已更新的内容。真丢脸... :-/
    猜你喜欢
    • 2021-11-03
    • 1970-01-01
    • 2014-05-29
    • 1970-01-01
    • 1970-01-01
    • 2013-10-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多