With django-filter, is there a quick way to support all possible lookups for fields?

Viewed 726

django-filter allows you to easily declare filterable fields of a model.

For example,

class UserFilter(django_filters.FilterSet):
    class Meta:
        model = User
        fields = ['username']

provides an exact lookup for the username field which is equivalent to this...

class UserFilter(django_filters.FilterSet):
    class Meta:
        model = User
        fields = {
            'username': ['exact']
        }

I'm looking for a way support all possible lookup filters given the field so that I don't have to do this:

class UserFilter(django_filters.FilterSet):
    class Meta:
        model = User
        fields = {
            "username": ["exact", "iexact", "contains", "icontains", "startswith", ..., etc.]
        }
3 Answers

Override the get_fields(...) class method of FilterSet class as,

import django_filters as filters
# If you are using DRF, import `filters` as
# from django_filters import rest_framework as filters


class AnyModelFilter(filters.FilterSet):
    class Meta:
        model = AnyModel
        fields = '__all__'

    @classmethod
    def get_fields(cls):
        fields = super().get_fields()
        for field_name in fields.copy():
            lookup_list = cls.Meta.model._meta.get_field(field_name).get_lookups().keys()
            fields[field_name] = lookup_list
        return fields

You can get all possible lookups of a field by django lookup up api

lookups_list = []

lookups = User._meta.get_field("username").get_lookups()
for lookup in lookups:
    lookups_list.append(lookup)

result of lookups_list:

['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'in', 'contains', 'icontains', 'startswith', 'istartswith', 'endswith', 'iendswith', 'range', 'isnull', 'regex', 'iregex']

So you can use it in your FilterSet

def fields_lookups(MyModel):
    lookups = {}

    fields = [x.name for x in MyModel._meta.fields] #<=1) get all fields names
    for field in fields:
        lookups[field] = [*MyModel._meta.get_field(
            field).get_lookups().keys()]            #<=2) add each field to a `dict`and set it vlaue to the lookups
    return lookups


class StatsticsView(ItemsView):
    queryset = MyModel.objects.all()
    serializer_class = StatisticSer

    filterset_fields = fields_lookups(MyModel) #<= ✅

    def get(self, request, *args, **kwargs):
        ....
    def put(self, request, *args, **kwargs):
        ....
    .
    .
    .


Related