Django 用 timedelta 注释日期并增加

问题描述 投票:0回答:2

我正在尝试查询所有过期的预订,但我没有像

end_date
这样的字段,我有
start_date
和总计
itinerary__days

这是我的询问:

import datetime
from django.db.models import Avg, Count, Min, Sum, FloatField, ExpressionWrapper, F, DateTimeField

trip = Booking.objects.annotate(
    end_date=ExpressionWrapper(
        F('start_date') + datetime.timedelta(days=F('itinerary__days')),
        output_field=DateTimeField()
    )
)

这些是我的模型:

class Itinerary(models.Model):
    days = models.PositiveSmallIntegerField(_("Days"), null=True, blank=True)


class Booking(models.Model):
    itinerary = models.ForeignKey(
        Itinerary,
        on_delete=models.CASCADE
    )
    start_date = models.DateField(_("Start Date"), null=True, blank=True)

    def get_end_date(self):
        return self.start_date + datetime.timedelta(days=self.itinerary.days)

你可能已经注意到我有一个方法来获取

end_date
get_end_date()

这就是为什么我尝试注释以获取结束日期并根据结束日期进行查询以获取过期预订。

在我的查询中,您可能会注意到这一行:

DateTime.timedelta(days=F('itineraray__days'))
所以你知道
timedelta
days 将参数类型作为整数,但传递了这个
itinerary__days
导致了错误。

这种情况有人可以帮助我吗?

django django-rest-framework django-orm
2个回答
0
投票

在 postgres 中你可以这样尝试:

qs = Booking.objects.annotate(
    end_date=ExpressionWrapper(
        F('start_date') + Cast(F("itinerary__days"), output_field=IntegerField()),
    output_field=DateField()
))

0
投票

对于那些尝试使用 MySQL 执行此操作的人,这将起作用:

class MinuteInterval(Func):
    template = "INTERVAL %(expressions)s MINUTE"

_end_date = F('start_date') + MinuteInterval(F('duration'))

qs.annotate(
    end_date=ExpressionWrapper(_end_date, output_field=DateTimeField()),
)

您可以将 MINUTE(并重命名该类)替换为您想要的任何时间单位,从 此列表

我不确定 Django 是否通过时间间隔和 F 表达式解决了这个问题,至少在我使用的版本中没有。查看生成的 SQL 后,它会将微秒间隔与给定字段相乘,这在 MySQL 中不起作用。正确的语法是在间隔函数内使用字段名称,因此这个自定义函数可以解决问题。

© www.soinside.com 2019 - 2024. All rights reserved.