Julien Mertz
Julien Mertz

Reputation: 485

Django using FilterSet for filtering on boolean values

On my website I have a page displaying the list of all products with a search engine built with FilterSet. Everything is working perfectly but I want to add one more search option. I want to be able to filter all products with an attribute set to True, but when the checkbox is not marked I want to dislay all the products. With checkbox, the filtering is working but like I said I want to display all the products when the box isn't marked. I know using checkbox is a bad way to do that because when the checkbox is not marked, it considered the value to be False. So I tried using RadioSelect but nothing is working, in my filter tab I only have the title of the radioselect and a white rectangle below but I can't write on it or do anything with it. So what do I have to use ?

Here is my code. The products I want to display are from the model Plat and the attribute is the attribute is_delivering from the model Chef that is linked to Plat with a foreign key in Plat.

models.py

class Chef(models.Model):
    is_delivering = models.BooleanField(verbose_name = "Livraison ?", default = False)

class Plat(models.Model):
    titre = models.CharField(max_length = 100)
    description = models.TextField(null = True)
    allergenes = models.TextField(null = True)
    prix = models.IntegerField(verbose_name = "Prix par portion")
    chef = models.ForeignKey('inscription.Chef', on_delete = models.CASCADE)
    date_prep = models.DateTimeField(default=timezone.now, verbose_name="Date et heure de préparation")
    nb_portions = models.IntegerField(verbose_name = "Nombre de portions disponibles")
    photo = models.ImageField(upload_to = "photos_plat/")
    is_ordered = models.BooleanField(default=False)

filters.py

class PlatFilter(django_filters.FilterSet):
    titre = django_filters.CharFilter(
        field_name='titre', label='Mot clé :', lookup_expr='icontains',
        widget=forms.TextInput(attrs={'class': 'form-control'}),
    )
    prix_min = django_filters.NumberFilter(
        field_name='prix', label='Prix minimum :', lookup_expr='gte',
        widget=forms.NumberInput(attrs={'class': 'form-control'}),
    )
    prix_max = django_filters.NumberFilter(
        field_name='prix', label='Prix maximum :', lookup_expr='lte',
        widget=forms.NumberInput(attrs={'class': 'form-control'}),
    )
    nb_portions = django_filters.NumberFilter(
        field_name='nb_portions', label='Nombre de portions minimum :', lookup_expr='gte',
        widget=forms.NumberInput(attrs={'class': 'form-control'}),
    )
    date_prep = django_filters.DateFilter(
        field_name='date_prep__date', label='Date de préparation (format JJ/MM/AAAA)', lookup_expr='exact',
        widget=forms.DateTimeInput(attrs={'class': 'form-control'}),
    )

    CHOICES = (('Oui', True), ('Non', False))

    is_delivering = django_filters.BooleanFilter(
        field_name='chef__is_delivering', label='Livraison comprise',
        widget=forms.RadioSelect(attrs={'class': 'form-control', 'choices': CHOICES}),
    )

    class Meta:
        model = Plat
        fields = ['titre', 'nb_portions', 'date_prep']

Thanks in advance !

EDIT (rendering problem) :

base.html

<div class="filters-body">
  <form method="get">
    <div class="well">
      <div class="row">
        <div class="col-md-12 pl-5 pb-4 pt-4 pr-5">
          {% csrf_token %}
          {% for field in filter.form %}
          <div class="fieldWrapper form-group" style="font-size: 150%">
            {{ field.label_tag }}
            {{ field }}
          </div>
          {% endfor %}

          <button type="submit" class="btn btn-primary">
            <span class="glyphicon glyphicon-search"></span> Rechercher
          </button>
        </div>
      </div>
    </div>
  </form>
</div>

Picture of the rendering problem : rendering problem

Upvotes: 4

Views: 4080

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476649

There are two problems here:

  1. the choices consist out of 2-tuples, but the first item is the value, and the second is the label; and
  2. the choices is not an attr of the RadioSelect, but a parmeter.

You can fix this with:

CHOICES = ((True, 'Oui'), (False, 'Non'))

is_delivering = django_filters.BooleanFilter(
    field_name='chef__is_delivering', label='Livraison comprise',
    widget=forms.RadioSelect(attrs={'class': 'form-control'}, choices=CHOICES),
)

Upvotes: 3

Related Questions