⚠ Django 1.9 now includes a built-in __date lookup. If possible, you should use that instead of the code below, which doesn't support timezones.
In my post last week on date lookups,
I ended with a promise to take a look at building a
django lookup (namely, a
__date lookup). Django includes
Lookup class, and to build your own lookup expressions,
all you really need to do is:
- define a
- write the
as_sqlmethod to define how your database should handle building the query
As promised, here's a quick example. Assume we have the following model (silly,
but simple) model. For illustration purposes, it has both a
DateTimeField. We'll build our lookup, so that it works with
from django.db import models class Meeting(models.Model): date = models.DateField() scheduled = models.DateTimeField()
Step 1: Let's build the lookup, which I'm going to
from django.db.models import Lookup class DateLookup(Lookup): """A custom lookup, that lets you query DateField and DateTimeFields by a date""" lookup_name = 'date' # This enables us to use __date='2015-10-18' in a query def as_sql(self, compiler, connection): # The left-hand-side (lhs) in the query's WHERE clause. It consists # of your app name and field name. e.g. '"myapp"."scheduled"' # In this case, the left-hand-side has no params. lhs, lhs_params = self.process_lhs(compiler, connection) # The right-hand-side (rhs) + its params will define the input used # in the query's WHERE clause. At this point, the rhs_params will # be a datetime object, e.g.: datetime(2015, 10, 18, 0, 0, tzinfo=
) rhs, rhs_params = self.process_rhs(compiler, connection) # Both PostgreSQL and MySQL have a DATE function that lets us query # by date. The where clause in the generated SQL will look something # like, WHERE DATE(scheduled) = '2015-10-18' params = lhs_params + rhs_params return 'DATE(%s) = %s' % (lhs, rhs), params
Step 2: Register it with the appropriate model field(s).
In this case, both the
The Django docs include an important note about registering custom lookups:
from django.db.models.fields import DateField, DateTimeField DateField.register_lookup(DateLookup) DateTimeField.register_lookup(DateLookup)
You will need to ensure that this registration happens before you try to create any querysets using it. You could place the implementation in a models.py file, or register the lookup in the ready() method of an AppConfig.
Now, open a django shell, and you can run a query like the following, which
queries against a date field. This should give you all the Meetings where
date = datetime.date(2015, 10, 18):
Or, you can do the following, which queries agains a datetime field, which
should give you all the meetings where the
There's more to custom lookups in Django, and I highly recommend reading through the custom lookups documentation because it also includes a really great example, as well.
Note: All the code in this post was written using Python 3.4 and Django 1.8.comments powered by Disqus