【问题标题】:Annotate Django queryset with previous Sunday based on row's date field根据行的日期字段用上周日注释 Django 查询集
【发布时间】:2018-10-21 04:16:01
【问题描述】:

我有一张桌子,上面有一组 Orders 我的客户制作的(购买,可以这么说)。

客户可以选择交货日期。该值存储在每个 Order 中的一个名为 Order.delivery_date 的字段中(没有太多创意)

class Order(BaseModel):
    customer = ForeignKey(Customer, on_delete=CASCADE, related_name='orders')
    delivery_date = DateField(null=True, blank=True)

我想用上一个星期日为该delivery_date 获取Orders 的查询集添加注释(主要是为了创建每周报告,每周“分桶”)

我想 “哦!我知道了!我会得到一周中的日期索引,然后我会用该周索引的天数减去 datetime.timedelta,然后我会用它来获取星期日(如 Python 的 .weekday() 函数)"

from server.models import *
import datetime
from django.db.models import F, DateField, ExpressionWrapper
from django.db.models.functions import ExtractWeekDay

Order.objects.filter(
    delivery_date__isnull=False
).annotate(
    sunday=ExpressionWrapper(
        F('delivery_date') - datetime.timedelta(days=ExtractWeekDay(F('delivery_date')) + 1),
        output_field=DateField()
    )
).last().sunday

但如果我这样做,我会在尝试“构造”时得到 TypeError: unsupported type for timedelta days component: CombinedExpressiontimedelta 表达式。

Extract 中不使用F 函数也没有什么区别:无论我使用Extract(F('delivery_date')) 还是Extract('delivery_date'),我都会遇到同样的错误

这是 Python 3.4,Django 2.0.3 优于 MySQL 5.7.21

我知道我总是可以获取 Order 对象并在 Python 中执行此操作(我什至有一个小辅助函数可以执行此操作)但最好从数据库中获取带有该注释的对象(也用于学习目的)

提前谢谢你。

【问题讨论】:

  • 我已经回答了我自己的问题,但如果有人有更好的建议,请随时回答。 ???我什至不太确定我的答案是可以做到的最好的,而且它肯定是非常特定于数据库的。如果有人有更便携(如果可能的话,更“基于 Django”)的解决方案,请发布它????

标签: python mysql django datetime django-queryset


【解决方案1】:

哦,我忘了extra

看起来应该这样做(至少对于 MySQL)

orders_q = Order.objects.filter(
    delivery_date__isnull=False
).extra(
    select={
        'sunday': "DATE_ADD(`delivery_date`, interval(1 - DAYOFWEEK(`delivery_date`)) DAY)"
    },
).order_by('-id')

它似乎有效:

for record in orders_q.values('sunday', 'delivery_date'):
    print("date: {delivery_date}, sunday: {sunday} is_sunday?: {is_sunday}".format(
        is_sunday=record['sunday'].weekday() == 6, **record)
    )

date: 2018-06-04, sunday: 2018-06-03 is_sunday?: True
date: 2018-05-30, sunday: 2018-05-27 is_sunday?: True
date: 2018-05-21, sunday: 2018-05-20 is_sunday?: True
date: 2018-06-04, sunday: 2018-06-03 is_sunday?: True

编辑:显然,extra 即将被弃用/不受支持。至少,不是很...呃...fondly received 由 Django 开发人员编写。也许改用RawSQL 会更好。实际上,我在尝试使用 extrasunday 注释进行进一步过滤时遇到了问题,而 RawSQL 方法却没有。

这似乎效果更好:

orders_q = orders_q.annotate(
    sunday=RawSQL("DATE_ADD(`delivery_date`, interval(1 - DAYOFWEEK(`delivery_date`)) DAY)", ())
)

这让我可以进一步注释...

orders_q.annotate(sunday_count=Count('sunday'))

我不知道为什么,但是当我使用extra 时,我会得到Cannot resolve keyword 'sunday' into field

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-09
    • 2016-04-04
    • 2012-09-10
    • 2018-09-15
    • 1970-01-01
    • 1970-01-01
    • 2021-10-17
    • 2017-07-09
    相关资源
    最近更新 更多