TL;DR: I want to add minutes to a datetime in postgres and can think of two ways to do it.
Consider the following django model:
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()
Note that end is computed dynamically in the database by adding start and duration. This does exactly what I want.
However, I want the UI for the duration to be a number input that gives the duration in minutes. My current approach is to use the following form field:
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)
This looks a little brittle to me. Is it also possible to store the duration as integer and transform it to a duration dynamically? Something like this:
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()