0

也许这实际上是一个错误,但由于找不到任何表明它已知的东西,我会假设我做错了什么。

我有一个模型,Study,它有一个日期时间字段以及一个描述优先级的对象的外键(基本上是一个名称/数字对,这样可以按数字排序并按名称查看)。

我想首先按优先级对研究对象进行排序(因此首先将它们分组为更高优先级),然后按日期时间,最旧的优先。这样,Stat 将位于列表的顶部,最旧的在前,依此类推。

使用我的测试数据库,它是 sqlite,这就像预期的那样工作:

ordered = ordered = models.Study.objects.all().order_by('arrived').order_by('-priority__priority')
for study in ordered:
    print(study.arrived, study.priority)

(datetime.datetime(2013, 5, 15, 23, 22, tzinfo=<UTC>), <StudyPriority: STAT>)
(datetime.datetime(2013, 5, 15, 23, 20, 51, 948639, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 15, 23, 21, 6, 674582, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 15, 23, 21, 21, 86984, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 15, 23, 21, 36, 234965, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 15, 23, 21, 59, 618850, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 15, 23, 22, 18, 991499, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 15, 23, 22, 26, 229715, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 15, 23, 22, 31, 150896, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 15, 23, 22, 35, 379259, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 15, 23, 22, 43, 207465, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 15, 23, 31, 42, 176697, tzinfo=<UTC>), None)

另一方面,使用生产数据库(postgres),事情......出错了:

ordered = models.Study.objects.all().order_by('arrived').order_by('-priority__priority')
for study in ordered:
    print(study.arrived, study.priority)

(datetime.datetime(2013, 5, 29, 22, 31, 45, tzinfo=<UTC>), None)
(datetime.datetime(2013, 5, 29, 22, 36, 15, tzinfo=<UTC>), <StudyPriority: STAT>)
(datetime.datetime(2013, 5, 29, 22, 36, 20, 520912, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 29, 22, 35, 18, 784721, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 29, 22, 35, 44, 540762, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 29, 22, 35, 51, 355645, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 29, 22, 35, 56, 800284, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 29, 22, 36, 2, 190325, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 29, 22, 36, 15, 137803, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 29, 22, 31, 44, 759514, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 29, 22, 37, 52, 264583, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 29, 22, 37, 54, 191852, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 29, 22, 37, 56, 385968, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 29, 22, 37, 57, 865427, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 29, 22, 38, 1, 959433, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 29, 22, 38, 4, 748306, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 29, 22, 36, 57, 562198, tzinfo=<UTC>), <StudyPriority: LOW>)
(datetime.datetime(2013, 5, 29, 22, 34, 37, 909631, tzinfo=<UTC>), <StudyPriority: LOW>)

最明显的烦恼是,无论出于何种原因,postgres 都会按此顺序首先选择“空”对象。'priority__priority' 是数值优先级值,最高 = 最高(因此在这种情况下,null 被视为无穷大,而在 sqlite 中,它被视为 -infinity)。这不是一个大问题,很容易实现一个烦人的解决方法来手动将它们移动到底部。

真正的问题是日期时间似乎没有排序!在“低”优先级对象中,时间遍布整个地图。

这可能是 ORM 中的某种错误,还是我在做一些可识别的错误,而这恰好不是 sqlite 的问题?

4

2 回答 2

1

我想你想这样做:

ordered = models.Study.objects.order_by('arrived', '-priority__priority')

https://docs.djangoproject.com/en/dev/ref/models/querysets/#order-by

于 2013-05-30T22:40:33.747 回答
1

monokut 关于如何正确链接 order_by 的答案是等式的一部分,另一部分是使 priority__priority NOT NULL。

您正在尝试对 NULLable 字段进行排序——这始终是特定于实现的猴子扳手。上面你试图推理为什么 NULL 是第一个或最后一个。它的排序规则在数据库之间是任意的,不是因为它“等于无穷大”,而是因为它不等于任何东西,甚至它本身。(顺便说一句,在 Postgres 中,如果你发出 raw() 查询,你可以指定 NULLS LAST 或 NULLS FIRST 来获得你想要的,但 Django 不提供 ORM 快捷方式。)

如果您需要对列进行排序,可靠的方法是使字段 NOT NULL 并为其提供一个默认值,明确表示“未定义”或“最后一个位置”,并在每个其他值之前/之后对该值进行排序,以便它以可预测的方式变得可排序。用更深层次的极客术语来说,这是一个域/类型问题,您试图在一个域中对一个 None 类型进行排序,该域不包含它作为成员,而不是在一个明确的“底部”值上。

在您的示例中,我将创建一个名为“LOWEST”的新优先级类型,将其设置为模型字段的默认值,并将 priority__priority 设置为 1000 或 0,具体取决于“LOWEST”相对于“LOW”的含义。然后用 LOWEST 替换每个 NULL 的情况,并将优先级字段更新为不为空。然后您的排序将在每个系统中按预期工作。(而且您不会对 NULL 传播表达式 nuking 等普遍的 SQL 刺激/惊喜持开放态度。)

于 2013-05-31T01:36:09.533 回答