Django offers a few fields that are exclusive to Postgres. I recently had to use DateRangeField which is an interesting alternative to doing the usual start_date
and end_date
.
If you’re using Django Rest Framework, you are probably familiar with django-filters. It’s a generic system for filtering Django QuerySets, though I’ve mostly used it in combination with DRF.
Timestamped
Tested with following versions:
- Django 1.11 (confident this will work with Django 2.1)
- django-filters 2.0.0 (won’t work with previous versions, because 2.0 release includes a reworked version of RangeWidget)
Requirements
Ranges are composed of lower and upper bounds that operate as a whole value. I want to be able to specify both bounds when filtering and get the objects that satisfy these exact values. By default, Django stores DateRangeField
in its canonical form [)
- lower inclusive and upper exclusive. In this case, I’m fine to specify and filter the bounds only in their canonical form. But it should be fairly easy to extend this to support different range types.
From the filters list I spot DateRangeFilter
and DateFromToRangeFilter
. DateRangeFilter
defines a list of choices to select from (like today, yesterday past week, etc), not exactly what I’m looking for. DateFromToRangeFilter
looks more appealing, as it allows filtering using the _after
and _before
suffixes. It will conveniently convert the passed strings to DateField
and do gte
and lte
lookups on the field. Still not exactly what I need.
Show me the code
In your app:
Explanation
Let’s start from the bottom - DateExactRangeFilter
. Since we are doing a regular lookup, we are inheriting directly from Filter
. The field_class
here is important, as it converts the raw values to a format and type we need, in this case DateRange
composed of start and end dates. The DateExactRangeWidget
lists the available suffixes.
Now you can do this /api/events?event_dates_start=2018-08-07&event_dates_end=2018-08-12
to filter all events that start and end exactly on these dates.
Warning
This solution is not ideal, because none of this documented. Django-filters doesn’t provide a guide on how to extend existing classes to add your own filters, fields or widgets. The details of how these objects behave might change with time, hence use this at your own risk.