首页 > 解决方案 > 如何通过 django 在 postgres 中为日期时间添加分钟

问题描述

TL;DR:我想在 postgres 中为日期时间添加分钟,并且可以想到两种方法来做到这一点。

考虑以下 django 模型:

from django.db import models


class AppointmentManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().annotate(
            end=models.ExpressionWrapper(
                models.F('start') + models.F('duration'),
                output_field=models.DateTimeField(),
            )
        )


class Appointment(models.Model):
    start = models.DateTimeField()
    duration = models.DurationField()

    objects = AppointmentManager()

请注意,这是通过添加和end在数据库中动态计算的。这正是我想要的。startduration

但是,我希望持续时间的 UI 是一个数字输入,以分钟为单位给出持续时间。我目前的方法是使用以下表单字段:

import datetime
from django import forms


class MinutesField(forms.DurationField):
    widget = forms.NumberInput

    def prepare_value(self, value):
        if isinstance(value, datetime.timedelta):
            return int(value.total_seconds() / 60)
        return value

    def to_python(self, value):
        if value in self.empty_values:
            return None
        if isinstance(value, datetime.timedelta):
            return value
        if isinstance(value, str):
            value = int(value, 10)
        return datetime.timedelta(seconds=value * 60)

这在我看来有点脆弱。是否也可以将持续时间存储为整数并动态转换为持续时间?像这样的东西:

class AppointmentManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().annotate(
            end=models.ExpressionWrapper(
                models.F('start') + models.Func(models.F('duration'), function='minutes'),
                output_field=models.DateTimeField(),
            )
        )

class Appointment(models.Model):
    start = models.DateTimeField()
    duration = models.IntegerField()

    objects = AppointmentManager()

标签: djangopostgresqldatetimeorm

解决方案


在这个答案中找到了解决方案:

class AppointmentManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().annotate(
            end=models.ExpressionWrapper(
                models.F('start') + datetime.timedelta(seconds=60) * models.F('duration'),
                output_field=models.DateTimeField(),
            )
        )

推荐阅读