GRS
GRS

Reputation: 3084

Django-Filter: Creating checkboxes for Boolean Field

Models.py

class Task(models.Model):
    online = models.BooleanField(blank=False)

I would like to use django-filter to create the following checkboxes in the form:

[] Online [] Physical

If form is empty or both are ticked, get Task.objects.all(). If only one is ticked, then do Task.objects.filter('Online'=True/False).

I tried to add the following:

import django_filters
from app.models import Task
from django.db import models

class TaskFilter(django_filters.FilterSet):
    online = django_filters.BooleanFilter(name='online', lookup_expr='isnull')

    class Meta:
        model = Task
        fields = ['online']
        filter_overrides = {
            models.BooleanField: { 
                'filter_class': django_filters.BooleanFilter,
                'extra': lambda f: {
                    'widget': forms.CheckboxInput,
                },
            },
        }

I tried the following widgets: Select, RadioSelect, CheckboxInput, but it seems I get the same output for all of them. I get a dropdown list e.g.

Online: [ Dropdown to select a value from Yes, No, Unknown ]

Upvotes: 2

Views: 7733

Answers (2)

Ishant Dahiya
Ishant Dahiya

Reputation: 111

Filters accept a widget argument, so you if you're manually instantiating filters, you can use:

class TaskFilter(django_filters.FilterSet):
    online = django_filters.filters.BooleanFilter(widget=forms.CheckboxInput)
    class Meta:
        model = Task
        fields = ['online']

However, if you're using the meta class to declare fields, then you can override the behavior with filter_overrides

class TaskFilter(django_filters.FilterSet):
    filter_overrides = {
        models.BooleanField: {
            'filter_class': filters.BooleanFilter,
            'extra': lambda f: {
                widget: forms.CheckboxInput
            },
        }
    }
    class Meta:
        model = MyModel
        fields = ['online']

After a lot of testing though, I came to a conclusion that is usually helpful for default=False model fields.

refer: django-filter issue

Upvotes: 3

inmate37
inmate37

Reputation: 1238

You can use choices for that kind of stuff:

TYPE_CHOICES = (
    (0, 'Online'),
    (1, 'Physical'),
)
class Task(models.Model):
    type = models.CharField(
        choices=TYPE_CHOICES, default=0, max_length=100
    )
    objects = TaskQuerySet().as_manager()

Then you can filter it as usual:

Task.objects.filter(type=0).filter(...)

And to make it more easier you may add a custom queryset class:

class TaskQuerySet(models.QuerySet):
    def get_online(self):
        return self.filter(type=0)

    def get_physical(self):
        return self.filter(type=1)

That will allow you to do things like:

Task.objects.get_online.filter(...)
Task.objects.get_physical.filter(...)

In the filters.py add:

type = django_filters.MultipleChoiceFilter(field_name='type', choices=CHOICES, widget=forms.CheckboxSelectMultiple)

Upvotes: 3

Related Questions