I have a datetime field in Django, and I want to filter this based on time. I don't care about the particular date, but I want to find all transactions before 7:30, for example.
I know I can filter by hour and minute such as:
Q(datetime__hour=7) & \
Q(datetime__minute=30)
However, this would find all transactions AT 7:30. You are also unable to apply gte or lte. ie
(Q(datetime__hour__lte=7) & \
Q(datetime__minute__lte=30)) | \
Q(datetime__hour__lt=7)
The only thing that appears to be a potential solution is to have many queries, such as:
(Q(datetime__hour=7) & \
(Q(datetime__minute=30) | \
Q(datetime__minute=29) | \
Q(datetime__minute=28) | \
....
Q(datetime__minute=2) | \
Q(datetime__minute=1) | \
Q(datetime__minute=0))) | \
Q(datetime__hour=6) | \
Q(datetime__hour=5) | \
Q(datetime__hour=4) | \
Q(datetime__hour=3) | \
Q(datetime__hour=2) | \
Q(datetime__hour=1) | \
Q(datetime__hour=0)
But this seems ridiculous.
Anyone have any ideas?
Just split the datetime field into a date and a time field. Than you can filter on time only:
from datetime import combine
class MyModel(models.Model):
start_date = models.DateField()
start_time = models.TimeField()
class Meta:
ordering = ['start_date', 'start_time']
def start_datetime(self):
return combine(self.date, self.time)
I added the Meta.ordering and start_datetime model method to show that this model can present data in the same way a model with a DateTimeField can.
Now you can filter on time:
objects = MyModel.objects.filter(start_time__lt=time(7, 30))
If you have a established project and many queries depend on having a normal DateTime field. Splitting the datetime into a date and time fields come a cost: Rewriting queries threw out your project. There is an alternative: Only add a time field and leave the datetime field untouched. A save method can add the time based on datetime. The down side is that you have duplicated data in your db. The good thing it solves your problem with minimal effort.
class MyModel(models.Model):
start_datetime = models.DateTimeField()
start_time = models.TimeField(blank=True)
def save(self)
self.start_time = self.start_datetime.time
All existing queries will be the same as before and filter on time only:
objects = MyModel.objects.filter(start_time__lt=time(7, 30))
In Django 1.7+ you could use a transform to extract minute and hour from the timestamp. See https://docs.djangoproject.com/en/1.7/howto/custom-lookups/#a-simple-transformer-example for details.
Not sure when the filter by time was introduced, but in recent versions of Django (4.0+) this is done by the following query syntax:
YourModel.objects.all().filter(datetime__hour__lte=7, datetime__minute__lte=30)
Where YourModel
is the model you are filtering, and datetime
is the field from that model.
Ideas:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.