Search code examples
pythondjangodjango-filters

How to display empty_label for non-mandatory fields with django-filter?


I've applied the basic example of django-filters with the following setup: models.py

class Shopper(models.Model):
    FirstName = models.CharField(max_length=30)     
    LastName = models.CharField(max_length=30)      
    Gender_CHOICES = (
        ('','---------'),
        ('Male','Male'),
        ('Female','Female'),
    )
    Gender = models.CharField(max_length=6, choices=Gender_CHOICES, default=None)
        School_CHOICES = (
        ('','---------'),
        (u'1', 'Primary school'),
        (u'2', 'High School'),
        (u'3', 'Apprenticeship'),
        (u'4', 'BsC'),
        (u'5', 'MsC'),
        (u'6', 'MBA'),
        (u'7', 'PhD'),
    )
    HighestSchool = models.CharField(max_length=40, blank = True, choices = School_CHOICES,default=None)

views.py:

def shopperlist(request):
    f = ShopperFilter(request.GET, queryset=Shopper.objects.all())
    return render(request,'mysapp/emailcampaign.html', {'filter': f})

urls.py:

   url(r'^emailcampaign/$', views.shopperlist, name='EmailCampaign'),

template:

{% extends "basewlogout.html" %}

{% block content %}
{% csrf_token %}
    <form action="" method="get">
    {{ filter.form.as_p }}
    <input type="submit" name="Filter" value="Filter" />
    </form>

        {% for obj in filter %}
            <li>{{ obj.FirstName }} {{ obj.LastName }} {{ obj.Email }}</li>
        {% endfor %}

       <a href="{% url 'UserLogin' %}"> 
       <p> Return to home page. </p> </a>
{% endblock %}

forms.py:

class ShopperForm(ModelForm):

    class Meta:
        model = Shopper

The empty choices ('','---------') were added to make sure django-filters will display it during filtering and let that field unspecified. However, for the non-mandatory HighestSchool field it displays twice when using the model in a create scenario with ModelForm. I.e. ('','---------') should not be listed for non-mandatory field. Then the empty_label cannot be selected during filtering...

How can this be solved with having one empty_label listed during the create view and have the possibility to leave both mandatory and non-mandatory fields unspecified during filtering?


Solution

  • You can accomplish this within the __init__ by updating the empty_label directly on the filter, thus avoiding the need to redefine all options.

    class FooFilter(django_filters.FilterSet):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.filters["some_choice_field"].extra.update(empty_label="All")
    
        class Meta:
            model = Foo
            fields = [
                "some_choice_field",
            ]