python 51 lines · 6 steps

Building a date-range FilterSet in Django

A django-filter FilterSet that combines explicit date bounds, quick-range presets, and a default ordering.

Explained by highlit
1import django_filters
2from django import forms
3from django.utils import timezone
4 
5from .models import Report
6 
7 
8class ReportFilter(django_filters.FilterSet):
9 created_after = django_filters.DateFilter(
10 field_name="created_at",
11 lookup_expr="date__gte",
12 label="From",
13 widget=forms.DateInput(attrs={"type": "date"}),
14 )
15 created_before = django_filters.DateFilter(
16 field_name="created_at",
17 lookup_expr="date__lte",
18 label="To",
19 widget=forms.DateInput(attrs={"type": "date"}),
20 )
21 period = django_filters.ChoiceFilter(
22 method="filter_period",
23 label="Quick range",
24 choices=[
25 ("7d", "Last 7 days"),
26 ("30d", "Last 30 days"),
27 ("ytd", "Year to date"),
28 ],
29 )
30 status = django_filters.MultipleChoiceFilter(choices=Report.Status.choices)
31 
32 class Meta:
33 model = Report
34 fields = ["created_after", "created_before", "period", "status"]
35 
36 def filter_period(self, queryset, name, value):
37 now = timezone.now()
38 if value == "7d":
39 start = now - timezone.timedelta(days=7)
40 elif value == "30d":
41 start = now - timezone.timedelta(days=30)
42 elif value == "ytd":
43 start = now.replace(month=1, day=1, hour=0, minute=0, second=0, microsecond=0)
44 else:
45 return queryset
46 return queryset.filter(created_at__gte=start)
47 
48 @property
49 def qs(self):
50 parent = super().qs
51 return parent.order_by("-created_at")
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Declarative filter fields map URL query parameters directly onto model lookups.
  2. 2A method filter lets you translate a friendly choice into arbitrary queryset logic.
  3. 3Overriding qs is the clean hook for applying a default ordering to every filtered result.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Building a date-range FilterSet in Django — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code