Django filter form appears by default as dropdown; change to checkbox

Viewed 371

I have a model defined like below in models.py

class ImageGrab(models.Model):
    title = models.CharField(max_length=50)
    slug=models.CharField(max_length=200)
    age=models.ForeignKey(Age, on_delete=models.CASCADE)
    gender=models.ForeignKey(Gender, on_delete=models.CASCADE)
    masked=models.ForeignKey(Mask, on_delete=models.CASCADE)
    withBackpack=models.ForeignKey(Backpack, on_delete=models.CASCADE)

Filters for which are defined as below in filters.py:

class ImageFilterAge(django_filters.FilterSet):
    class Meta:
        model = ImageGrab
        fields = ['age']

###others similar to this 

class ImageFilter(django_filters.FilterSet):
    class Meta:
        model = ImageGrab
        fields = ['age', 'gender', 'masked', 'withBackpack']

The view is like below defined in views.py

def images(request):
    imagelist = ImageGrab.objects.all()
    imagefilter = ImageFilter(request.GET, queryset=imagelist)
    agefilter = ImageFilterAge(request.GET, queryset=imagelist)
    genderfilter=ImageFilterGender(request.GET, queryset=imagelist)
    maskedfilter= ImageFilterMask(request.GET, queryset=imagelist)
    backpackfilter = ImageFilterBackpack(request.GET, queryset=imagelist) 
    return render(request, 'imglist.html', {'filter': imagefilter,'agefilter': agefilter.form, 'genderfilter':genderfilter.form, 'maskfilter':maskedfilter.form, 'backpackfilter':backpackfilter.form})

My template is like this, in imglist.html

<form method="get" name="search" id="search">
    {{ agefilter }} <br>
    {{ genderfilter }} <br>
    {{ maskfilter }} <br>
    {{ backpackfilter }} <br>
</form>

This is rendered by default as dropdown select form as given in image link below. I want to change this to say checkbox multiple select and/ or radio button for the filters. Filtering Using Dropdown

How to go about doing this?

Thanks in advance.

3 Answers

I combined the two solutions given by both users above, and got the solution thus:

Filters.py:

age = ModelMultipleChoiceFilter(queryset=Age.objects.all(),widget=forms.CheckboxSelectMultiple())

Models.py

class Age(models.Model):
    ageChoices=(
        ('Child', 'Child'),
        ('Adult', 'Adult'),
        ('Old', 'Old'),
    )
    age = models.CharField(max_length=5, choices=ageChoices)

What is good is that the filters seem to wok neatly on the data set as well.

Thanks to users Abdul Aziz Barkat & Vosem

enter image description here

Seeing how your models are set up you might want to create a django custom form on which you specify the fields and the input method for each field.

Although you also might want to rethink using Foreign Keys for something as simple as age, gender or withBackpack. You probably want to use other kinds of fields for those, like IntegerField or BooleanField

You can customize the filter generation by specifying filter_overrides in the filter sets Meta. So for your use you can do something like below to set CheckboxInput as the widget to be used:

from django import forms
from django.db import models


class ImageFilterAge(django_filters.FilterSet):
    class Meta:
        model = ImageGrab
        fields = ['age']
        filter_overrides = {
            models.ForeignKey: {
                'filter_class': django_filters.ModelChoiceFilter,
                'extra': lambda f: {
                    'widget': forms.CheckboxInput,
                },
            },
        }

You can also explicitly define the filter field to be able to specify it's widget:

from django import forms


class ImageFilterAge(django_filters.FilterSet):
    age = django_filters.ModelChoiceFilter(queryset=Age.objects.all(), widget=forms.CheckboxInput)
    class Meta:
        model = ImageGrab
        fields = ['age']
Related