如何以天为单位对日期时间的差异进行注释



我有一个Booking模型,它有startend日期时间字段。我想知道一次预订的有效期是多少天。我可以在Python中做到这一点,但我需要这个值来进行进一步的注释。

以下是我尝试过的:

In [1]: Booking.objects.annotate(days=F('end')-F('start'))[0].days
Out[1]: datetime.timedelta(16, 50400)

这里有几个问题:

  • 我想要一个整数(或我可以在计算中使用的其他数字类型)作为输出,而不是时间增量。设置output_field在这里没有任何意义
  • 我的总和基于日期。像这样的减法,如果不去掉时间,可能会导致总天数的休假

在Python中,我会做(end.date() - start.date()).days + 1。我如何在数据库中做到这一点,最好是通过ORM(例如数据库函数),但RawSQL就足以解决这个问题?

我已经编写了几个数据库函数来转换和截断日期,以解决PostgreSQL下的这两个问题。我使用的DATE_PARTDATE_TRUNC内部函数是特定于DB的☹

from django.db.models import Func
class DiffDays(Func):
    function = 'DATE_PART'
    template = "%(function)s('day', %(expressions)s)"
class CastDate(Func):
    function = 'date_trunc'
    template = "%(function)s('day', %(expressions)s)"

然后我可以:

In [25]: Booking.objects.annotate(days=DiffDays(CastDate(F('end'))-CastDate(F('start'))) + 1)[0].days
Out[25]: 18.0

这个问题还有另一个简单的解决方案。您可以使用:

from django.db.models import F
from django.db.models.functions import ExtractDay

然后:

Booking.objects.annotate(days=(ExtractDay(F('end')-F('start'))+1))[0].days

我知道这已经很长时间了,但如果有人在调查它,这对我来说是有效的

from django.db.models import DurationField, ExpressionWrapper, F, DateTimeField
from django.db.models.functions import Extract
MyModel.objects.annotate(
    duration=ExpressionWrapper(
        F('end_date') - F('start_date'),
        output_field=DurationField()
    )
).annotate(
    duration_in_days=Extract('duration', 'day')
)

对于我的案例,我试图获得当前日期和字段之间的差异,我使用了以下

from django.utils import timezone
today = timezone.now().date()
qs.annotate(
        duration=ExpressionWrapper(
            Cast(today, DateTimeField()) - F('date'),
            output_field=DurationField()
        )
    ).annotate(
        duration_in_days=Extract('duration', 'day')
    )

如果您使用MYSQL数据库,您可以使用自定义数据库函数作为

from django.db.models.functions import Func

class TimeStampDiff(Func):
    class PrettyStringFormatting(dict):
        def __missing__(self, key):
            return '%(' + key + ')s'
    def __init__(self, *expressions, **extra):
        unit = extra.pop('unit', 'day')
        self.template = self.template % self.PrettyStringFormatting({"unit": unit})
        super().__init__(*expressions, **extra)
    function = 'TIMESTAMPDIFF'
    template = "%(function)s(%(unit)s, %(expressions)s)"



用法

from django.db.models import F, IntegerField
booking_queryset = Booking.objects.annotate(
    days=TimeStampDiff(F('start'), F('end'), output_field=IntegerField()))
if booking_queryset.exist():
    print(booking_queryset[0].__dict__)

相关内容

  • 没有找到相关文章