【问题标题】:Applying an arbitrary sort to Django ORM querysets对 Django ORM 查询集应用任意排序
【发布时间】:2013-11-07 10:25:11
【问题描述】:

我有一个数据库表,其中包含代表年度重复事件的项目集。记录集按月和日存储。我经常需要检索与一系列日历日期相对应的事件记录。我正在使用 Django ORM 来处理记录,所以目前我将日期转换为相应的 Q 对象(例如 Q(month=month, day=day) 并在对 MyModel.objects.filter() 的调用中将它们组合在一起。

如果我的日期范围与新年相交,就会出现问题。如果我想要从 2013 年 12 月 31 日到 2014 年 1 月 1 日的事件,我会这样做:

MyModel.objects.filter(Q(month=12, day=31) | Q(month=1, day=1))

但我按顺序得到结果:

month = 1, day = 1
month = 12, day = 31

相反,我想按顺序获得结果:

month = 12, day = 31
month = 1, day = 1

出于不必要地使问题复杂化的原因,我不能简单地将查询分成两个查询,每年一个。我想进行一次查询并按所需顺序获取结果。如有必要,我可以重新编写查询。

我知道extra 应该很有用,但我不太明白如何使用它。

更新:

为了更接近预期的解决方案,强制执行绝对排序,我可以以某种方式将Julian Day 作为“计算”字段滑入结果中,并按该字段排序。但是该怎么做呢?

【问题讨论】:

  • year 字段吗?
  • 不,否则这将是微不足道的。 :) 这些记录代表每年都会发生的事件。
  • 这个查询是否允许加入? (我的意思是它会影响性能吗?)
  • 我不明白为什么不这样做。我愿意至少尝试一下。
  • 范围是否总是跨越两个月,还是可以有任意长度?

标签: python sql django sorting orm


【解决方案1】:

我有棘手的解决方案使用 extra 和 SQL CASE 语句:

start_month = 12
start_day = 31
end_month = 1
end_day = 1
query = (models.MyModel.objects.filter(Q(month=start_month, day=start_day) | 
                                       Q(month=end_month, day=end_day))
                       .extra(select={'order_me': '''CASE WHEN month*31+day < %s*31+%s 
                                                          THEN (12+month)*31+day 
                                                          ELSE (month)*31+day
                                                   END''' % (start_month, start_day)})
                       .extra(order_by=['order_me']))

一旦我添加了这个 order_me 字段(这不太好),我认为它应该用于谓词而不是 Q(...)|Q(...) 用于日期范围

query = (models.MyModel.objects.all()
                   .extra(select={'order_me': """CASE WHEN month*31+day < %s*31+%s 
                                                    THEN (12+month)*31+day 
                                                    ELSE (month)*31+day
                                               END""" % (start_month, start_day) })
                   .extra(order_by=['order_me'])
                   .extra(where=['order_me < (12 + %s) * 31 + %s' % (end_month,
                                                                     end_day)]))

【讨论】:

  • 确实很棘手。但是month*31+day不会总是小于12*31+31吗?
  • 不,有时它是相等的,但你是对的,我已经解决了这个问题
  • 是的,第二个公式看起来不错,而且和我预期的一样脏。 :)
  • 我的回答对你有帮助吗?
  • 您回答了我提出的问题,这非常有帮助。 :) 我还有其他更复杂的要求,这使得该解决方案不适用于我的特定情况,但这至少可以帮助我排除 SQL 作为我需要做的所有事情的地方。
猜你喜欢
  • 1970-01-01
  • 2013-09-26
  • 2021-07-25
  • 1970-01-01
  • 2010-11-01
  • 1970-01-01
  • 2012-03-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多