I am trying to filter a DateTimeField
comparing with a date. I mean:
MyObject.objects.filter(datetime_attr=datetime.date(2009,8,22))
I get an empty queryset list as an answer because (I think) I am not considering time, but I want “any time”.
Is there an easy way in Django for doing this?
I have the time in the datetime setted, it is not 00:00
.
2
19 Answers
Such lookups are implemented in django.views.generic.date_based
as follows:
{'date_time_field__range': (datetime.datetime.combine(date, datetime.time.min),
datetime.datetime.combine(date, datetime.time.max))}
Because it is quite verbose there are plans to improve the syntax using __date
operator. Check “#9596 Comparing a DateTimeField to a date is too hard” for more details.
3
Using with range:
Q(created__gte=datetime.combine(created_value, time.min))
– DingoLooks like it will land in Django 1.9: github.com/django/django/commit/…
– amjoconnNew in Django 1.9:
Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
– Non
YourModel.objects.filter(datetime_published__year="2008",
datetime_published__month="03",
datetime_published__day='27')
// edit after comments
YourModel.objects.filter(datetime_published=datetime(2008, 03, 27))
doest not work because it creates a datetime object with time values set to 0, so the time in database doesn’t match.
7
thx for the answer! the first alternative doesn’t work with datetimefields. The second alternative works ;). If someone knows another method please answer
–docs.python.org/library/datetime.html#datetime-objects using datetime() from datetime module hrs,mins,secs is optional. the second is from a working project with vars replaced, you can look in the docs it’s correct
– zalewi know it is optional, the problem is that my datetimefield has the time setted, it is not 00:00
–“the first alternative doesn’t work with datetimefields.” it’d be quite surprising, as datetime.datetime() returns a datetime object djangoproject.com/documentation/0.96/models/basic check the model definition and examples: pub_date = models.DateTimeField() pub_date=datetime(2005, 7, 30)
– zalew“i know it is optional, the problem is that my datetimefield has the time setted, it is not 00:00” Oh, now i get it. Yes, with no time arguments it sets to 00, so it does not return 🙂
– zalew
Here are the results I got with ipython’s timeit function:
from datetime import date
today = date.today()
timeit[Model.objects.filter(date_created__year=today.year, date_created__month=today.month, date_created__day=today.day)]
1000 loops, best of 3: 652 us per loop
timeit[Model.objects.filter(date_created__gte=today)]
1000 loops, best of 3: 631 us per loop
timeit[Model.objects.filter(date_created__startswith=today)]
1000 loops, best of 3: 541 us per loop
timeit[Model.objects.filter(date_created__contains=today)]
1000 loops, best of 3: 536 us per loop
contains seems to be faster.
3
This solution seems to be the most recent. I am surprised it got 4 upvotes, because when I try the
contains
solution, I get the error message:Unable to get repr for <class 'django.db.models.query.QuerySet'>
– HoumanI recheck and update the results today and I don’t think your error it’s caused by the
__contains
filter. But if you’re running into issues you should try the django docs example which is using__gte
.– MorenoThe __contains method works fine for me. I think this is probably the best answer since it provides performance comparisons. I’ve voted more than one, but I’m surprised it doesn’t have more upvotes.
Now Django has __date queryset filter to query datetime objects against dates in development version. Thus, it will be available in 1.9 soon.
3
Yup, it was added in 1.9 docs.djangoproject.com/en/1.9/ref/models/querysets/#date
Best answer, valid for newer Django versions
– serfer2This does not work for me, no idea why 🙁 I’m on django 1.11 My exact exception is: NotImplementedError: subclasses of basedatabaseoperations may require a datetime_cast_date() method
Mymodel.objects.filter(date_time_field__contains=datetime.date(1986, 7, 28))
the above is what I’ve used. Not only does it work, it also has some inherent logical backing.
1
Much better than all of the other answers here, thanks!
– Kin
As of Django 1.9, the way to do this is by using __date
on a datetime object.
For example:
MyObject.objects.filter(datetime_attr__date=datetime.date(2009,8,22))
1
I read several answers stating about the ‘__date’ , but I found all of them quite sophisticated, until I read your answer. It’s simple and straight to the point.
This produces the same results as using __year, __month, and __day and seems to work for me:
YourModel.objects.filter(your_datetime_field__startswith=datetime.date(2009,8,22))
1
looks like this one turns date object to string and do a string comparison of dates therefore forces db to do a full table scan. for big tables this one kill your performance
assuming active_on is a date object, increment it by 1 day then do range
next_day = active_on + datetime.timedelta(1)
queryset = queryset.filter(date_created__range=(active_on, next_day) )
You can do like this
MyObject.objects.filter(datetime_field__date=datetime.date(2009,8,22))
or if you want to filter between 2 dates
MyObject.objects.filter(
datetime_field__date__range=(datetime.date(2009,8,22), datetime.date(2009,9,22))
)
There’s a fantastic blogpost that covers this here: Comparing Dates and Datetimes in the Django ORM
The best solution posted for Django>1.7,<1.9 is to register a transform:
from django.db import models
class MySQLDatetimeDate(models.Transform):
"""
This implements a custom SQL lookup when using `__date` with datetimes.
To enable filtering on datetimes that fall on a given date, import
this transform and register it with the DateTimeField.
"""
lookup_name="date"
def as_sql(self, compiler, connection):
lhs, params = compiler.compile(self.lhs)
return 'DATE({})'.format(lhs), params
@property
def output_field(self):
return models.DateField()
Then you can use it in your filters like this:
Foo.objects.filter(created_on__date=date)
EDIT
This solution is definitely back end dependent. From the article:
Of course, this implementation relies on your particular flavor of SQL having a DATE() function. MySQL does. So does SQLite. On the other hand, I haven’t worked with PostgreSQL personally, but some googling leads me to believe that it does not have a DATE() function. So an implementation this simple seems like it will necessarily be somewhat backend-dependent.
3
is this MySQL specific? wondering about the class name choice.
– Binoj D@BinojDavid Yeah, it is backend dependent
I tested it using Django 1.8 and PostgreSQL 9.6.6 and it works perfectly. Actually using PostgreSQL you can also use this syntax:
return '{}::date'.format(lhs), params
Here is an interesting technique– I leveraged the startswith procedure as implemented with Django on MySQL to achieve the result of only looking up a datetime through only the date. Basically, when Django does the lookup in the database it has to do a string conversion for the DATETIME MySQL storage object, so you can filter on that, leaving out the timestamp portion of the date– that way %LIKE% matches only the date object and you’ll get every timestamp for the given date.
datetime_filter = datetime(2009, 8, 22)
MyObject.objects.filter(datetime_attr__startswith=datetime_filter.date())
This will perform the following query:
SELECT (values) FROM myapp_my_object
WHERE myapp_my_object.datetime_attr LIKE BINARY 2009-08-22%
The LIKE BINARY in this case will match everything for the date, no matter the timestamp. Including values like:
+---------------------+
| datetime_attr |
+---------------------+
| 2009-08-22 11:05:08 |
+---------------------+
Hopefully this helps everyone until Django comes out with a solution!
1
Ok, so this does appear to be the same answer as mhost and kettlehell above, but with more description of what is happening in the backend. At least you have a reason to use contains or startswith along with the date() attribute of the datetime!
Hm.. My solution is working:
Mymodel.objects.filter(date_time_field__startswith=datetime.datetime(1986, 7, 28))
Model.objects.filter(datetime__year=2011, datetime__month=2, datetime__day=30)
0
In Django 1.7.6 works:
MyObject.objects.filter(datetime_attr__startswith=datetime.date(2009,8,22))
1
This only works if you’re looking for the exact date, you can’t use
__lte
for example.
See the article Django Documentation
ur_data_model.objects.filter(ur_date_field__gte=datetime(2009, 8, 22), ur_date_field__lt=datetime(2009, 8, 23))
1
in the django documentation it works because the datetimefiled has time 00:00
–
person = Profile.objects.get(id=1)
tasks = Task.objects.filter(assigned_to=person, time_stamp__year=person.time_stamp.utcnow().year)
all my model do have time_stamp so I used the person objects to obtain the current year
You can filter between some day ranges
2016-01-01 00:00:00 <--> 2016-04-01 23:59:59.99999
User.objects.filter(date_joined__gte=datetime.combine(datetime.strptime('2016-
01-01', '%Y-%d-%m'), datetime.min.time()),
date_joined__lte=datetime.combine(datetime.strptime('2016-04-01', '%Y-%d-%m'),
datetime.max.time())).count()
2016-01-01 00:00:00 <--> 2016-01-14 00:00:00
User.objects.filter(date_joined__gte="2016-01-01", date_joined__lte="2016-1-14").count()
You can filter by the Date as per as the date format is the same with your django date format. Default format is ISO YYYY-MM-DD
target_date = "2009-08-22"
qs = MyObject.objects.filter(datetime_attr__date=target_date)
Just as simple as that if you have a datetimefield your can use datetime.date.today()
context['now'] = Mymodel.objects.filter(date_time_field=datetime.date.today())
This is one of annoyances of Django. Considering this is a simple and common use case, there’s no simple way to achieve this.
Related: stackoverflow.com/a/22085678/2859614