Search code examples
pythondjangodjango-filter

Fitler DateTimeField with DateFilter in django-filter


I have a model which has create_date, update_date, release_date DateTimeField.

I wish to have the filter to filter these DateTimeField with DateFilter. Here is one way I can do that:

class ProductFilter(django_filters.FilterSet):
    
    create_date = DateFilter(field_name='create_date', lookup_expr='date')
    create_date__gt = DateFilter(field_name='create_date', lookup_expr='date__gt')
    create_date__lt = DateFilter(field_name='create_date', lookup_expr='date__lt')
    create_date__gte = DateFilter(field_name='create_date', lookup_expr='date__gte')
    create_date__lte = DateFilter(field_name='create_date', lookup_expr='date__lte')
    
    update_date = DateFilter(field_name='update_date', lookup_expr='date')
    update_date__gt = DateFilter(field_name='update_date', lookup_expr='date__gt')
    update_date__lt = DateFilter(field_name='update_date', lookup_expr='date__lt')
    update_date__gte = DateFilter(field_name='update_date', lookup_expr='date__gte')
    update_date__lte = DateFilter(field_name='update_date', lookup_expr='date__lte')

    release_date = DateFilter(field_name='release_date', lookup_expr='date')
    release_date__gt = DateFilter(field_name='release_date', lookup_expr='date__gt')
    release_date__lt = DateFilter(field_name='release_date', lookup_expr='date__lt')
    release_date__gte = DateFilter(field_name='release_date', lookup_expr='date__gte')
    release_date__lte = DateFilter(field_name='release_date', lookup_expr='date__lte')

You may see that things get repetitive. Is there any way to encapsulate the logic?

P.S. I know I can use Meta.fields like:

class ProductFilter(django_filters.FilterSet):
    class Meta:
        model = Product
        fields = {
            'create_date': ['date', 'date__gt', 'date__lt', 'date__gte', 'date__lte'],
            'update_date': ['date', 'date__gt', 'date__lt', 'date__gte', 'date__lte'],
            'release_date': ['date', 'date__gt', 'date__lt', 'date__gte', 'date__lte'],
        }

but the filter name will become create_date__date instead of create_date.


Solution

  • You can override the __init__(...) method of the FilterSet class as,

    field_names = ["create_date", "update_date", "release_date"]
    lookup_expr = ["gt", "lt", "gte", "lte"]
    filter_dict = {}
    for field_name in field_names:
        filter_dict[field_name] = DateFilter(lookup_expr="date")
        for expr in lookup_expr:
            filter_dict[f"{field_name}_{expr}"] = DateFilter(
                field_name=field_name,
                lookup_expr=f"date__{expr}"
            )
    
    
    class FooFilter(filters.FilterSet):
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.filters.update(filter_dict)