基于行的日期字段,使用上一个星期日注释Django查询集

时间:2018-05-10 19:54:41

标签: python mysql django datetime django-queryset

我的桌子上有一组Orders我的客户制作的(购买,也就是说)。

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

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

我想注释一个查询集,该查询集在前一个星期日为Orders提取delivery_date(主要是创建每周报告," bucketized"每周)

我想"哦!我知道!我将在一周内获得日期索引,并且我将使用该周索引的天数减去datetime.timedelta,并且我将使用它来获取星期日(如Python&) #39; s .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: CombinedExpression表达式时得到timedelta

不使用F中的Extract功能也不会产生任何影响:无论是否使用Extract(F('delivery_date'))Extract('delivery_date'),我都会收到同样的错误

这是一个Python 3.4,使用Django 2.0.3而不是MySQL 5.7.21

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

提前谢谢。

1 个答案:

答案 0 :(得分: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代替。实际上,我在尝试使用sunday注释进行进一步过滤时遇到了问题extra我没有使用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