user11232156
user11232156

Reputation:

Django: How to limit TimeField to hours and minutes only (comparison issue)

I'm developping a web api using django, I have a TimeField that stores hours:minutes:seconds, since it will be compared to a hours:minutes (without seconds) coming from the mobile app, the comparison will always fail.

here is a comparison without seconds which is returnning an empty QuerySet:

>>> journey = Journey \
...        .objects \
...        .filter((Q(route__departStation=1) | Q(route__stop__station_id=1)),
...                (Q(route__arrivalStation=1) | Q(route__stop__station_id=1)),
...                route__departDate="2019-07-31", route__departTime="10:57")
>>> journey
<QuerySet []>

and here is when I add seconds to the comparison:

>>> journey = Journey \
...        .objects \
...        .filter((Q(route__departStation=1) | Q(route__stop__station_id=1)),
...                (Q(route__arrivalStation=1) | Q(route__stop__station_id=1)),
                route__departDate="2019-07-31", route__departTime="10:57:05")
>>> journey
<QuerySet [<Journey: Journey object (1)>]>

so please, how can I prevent the seconds from being saved to the database from this TimeField(), or at least how can I limit the comparison to hours and minutes only.

Upvotes: 1

Views: 1452

Answers (2)

mbijou
mbijou

Reputation: 87

In the model you can basically override the save method, take the timefield attribute and override it with a new datetime.time object, but without storing the seconds in it.

Here is an example:

from django.db import models
from datetime import time

class Route(models.Model):
    departTime = models.TimeField(null=True, blank=True)

    def save(self, *args, **kwargs):
        self.departTime = time(hour=self.departTime.hour, minute=self.departTime.minute)
        return super().save(*args, **kwargs)

However, bare in mind, that the save method is not going to be called when you are using bulk operations to create Route objects or update on querysets. In those cases you can make use of manager classes to override for instance the bulk_create or bulk_update methods or QuerySet to override the update method and only store hours and minutes there.

Upvotes: 0

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477641

You can use a TruncMinute expression [Django-doc] here:

from django.db.models.functions import TruncMinute

journeys = Journey.objects.annotate(
    depart_minute=TruncMinute('route__departTime')
).filter(
    (Q(route__departStation=1) | Q(route__stop__station_id=1)),
    (Q(route__arrivalStation=1) | Q(route__stop__station_id=1))
    route__departDate='2019-07-31', depart_minute='10:57'
)

That being said, I suggest you use a DateTimeField over a DateField and TimeField. Time actually only makes sense in combination with a date (and timezone). Many countries have daylight saving time (DST), or have changed their timezone throughout history. Therefore it is better to combine these.

Upvotes: 1

Related Questions