carltongibson / django-filter

A generic system for filtering Django QuerySets based on user selections
https://django-filter.readthedocs.io/en/main/
Other
4.46k stars 769 forks source link

Cannot override CharFilter for EmailFields #1524

Closed Enorio closed 2 years ago

Enorio commented 2 years ago

I'm using the django-filter 21.1.

I have the following model:

class Foo(models.Model):
    invitation_email = models.EmailField('email address', db_index=True, null=True)
    name = models.CharField(null=True, max_length=100)

What I want is to query Foo using icontains, so I've created this class:

class FooFilter(filters.FilterSet):
    class Meta:
        model = Foo
        fields = ['name', 'invitation_email']
        filter_overrides = {
            models.CharField: {
                'filter_class': filters.CharFilter,
                'extra': lambda f: {
                    'lookup_expr': 'icontains',
                },
            },
        }

The problem is that the lookup_expr for CharField is not being changed to icontains for the invitation_email, only for the name. I've done some debug, and when listing the filters of the FooFilter, it shows this problem.

The workaround I found for both to use the icontains was this:

class FooFilter(filters.FilterSet):
    invitation_email = filters.CharFilter(lookup_expr='icontains')

    class Meta:
        model = Foo
        fields = ['name', 'invitation_email']
        filter_overrides = {
            models.CharField: {
                'filter_class': filters.CharFilter,
                'extra': lambda f: {
                    'lookup_expr': 'icontains',
                },
            },
        }

Am I doing something wrong that I'm not seeing?

carltongibson commented 2 years ago

models.EmailField is mapped separately to models.CharField (in filtersets.py) so that's why you're seeing what you are.

Enorio commented 2 years ago

Ok. So i just need to add a filter override for the EmailField:

class FooFilter(filters.FilterSet):
    class Meta:
        model = Foo
        fields = ['name', 'invitation_email']
        filter_overrides = {
            models.CharField: {
                'filter_class': filters.CharFilter,
                'extra': lambda f: {
                    'lookup_expr': 'icontains',
                },
            models.EmailField: {
                'filter_class': filters.CharFilter,
                'extra': lambda f: {
                    'lookup_expr': 'icontains',
                },
            },
            },
        }

Got it. Thanks :wink: