Search code examples
djangodjango-filters

How can I specify custom choices for the django_filters DateRangeFilter function?


I am using the django_filters DateRangeFilter() function. My filter class looks like this:

class ListingFilter(django_filters.FilterSet):
    ship_docking = django_filters.DateRangeFilter()
    class Meta:
        model = Listing
        fields = ['orig', 'dest', 'ship_sailing', 'ship_docking']

I want to change the choices of range - default choices are Today, Yesterday, Past 7 days, etc. How can I specify a different list of choices?

Thanks and regards...Paul (Django newbie)


Solution

  • Checking out the source code for django-filter and the DateRangeFilter, we can see that on __init__ it checks if a choices set and a filters set has been passed in, if they are empty, it uses the defaults.

    class DateRangeFilter(ChoiceFilter):
        choices = [
                ('today', _('Today')),
                ('yesterday', _('Yesterday')),
                ('week', _('Past 7 days')),
                ('month', _('This month')),
                ('year', _('This year')),
            ]
        
            filters = {
                'today': lambda qs, name: qs.filter(**{
                    '%s__year' % name: now().year,
                    '%s__month' % name: now().month,
                    '%s__day' % name: now().day
                }),
                'yesterday': lambda qs, name: qs.filter(**{
                    '%s__year' % name: (now() - timedelta(days=1)).year,
                    '%s__month' % name: (now() - timedelta(days=1)).month,
                    '%s__day' % name: (now() - timedelta(days=1)).day,
                }),
                'week': lambda qs, name: qs.filter(**{
                    '%s__gte' % name: _truncate(now() - timedelta(days=7)),
                    '%s__lt' % name: _truncate(now() + timedelta(days=1)),
                }),
                'month': lambda qs, name: qs.filter(**{
                    '%s__year' % name: now().year,
                    '%s__month' % name: now().month
                }),
                'year': lambda qs, name: qs.filter(**{
                    '%s__year' % name: now().year,
                }),
            }
        
            def __init__(self, choices=None, filters=None, *args, **kwargs):
                if choices is not None:
                    self.choices = choices
                if filters is not None:
                    self.filters = filters
    

    All you have to do is create a list of sets for your choices and then copy the format for your custom filters and then:

    class ListingFilter(django_filters.FilterSet):
        // Put custom choices and filter variables here
        choices = [...]
        filters = { ... }
        ship_docking = django_filters.DateRangeFilter(choices=choices, filters=filters)
        class Meta:
            model = Listing
            fields = ['orig', 'dest', 'ship_sailing', 'ship_docking']