Multiple choice for filter and multiple models in filter?

Hello

I’m using the django-filter extension to filter the records of my queryset. So far, I have only used fields from a single model. But I would also like to be able to filter data that is connected to this model via an FK. How do I do that?

It’s about these two models.

class Responsibility(models.Model):
    project = models.ForeignKey(Project, on_delete=models.CASCADE, verbose_name='Projekt')
    system = models.ForeignKey(System, on_delete=models.CASCADE, verbose_name='Baugruppe')
    team = models.ForeignKey(Team, on_delete=models.CASCADE, verbose_name='Team')
    employee = models.ForeignKey(Employee, on_delete=models.SET_NULL, blank=True, null=True, verbose_name='Mitarbeiter')
    created_at = models.DateTimeField(auto_now_add=True, editable=False, blank=True, verbose_name='Erstelldatum')
    updated_at = models.DateTimeField(auto_now=True, editable=False, blank=True, verbose_name='Änderungsdatum')

    class Meta:
        verbose_name = 'Verantwortlichkeit'
        verbose_name_plural = 'Verantwortlichkeiten'
        constraints = [
            models.UniqueConstraint(fields=['project', 'system', 'team', 'employee'], name='uq_project_system_team_employee')
        ]

    def __str__(self):
        return f'{self.project} | {self.system} | {self.team} | {self.employee}'


class Status(models.Model):
    COLORS = (
        ('Rot', 'Rot'),
        ('Gelb', 'Gelb'),
        ('Grün', 'Grün'),
    )   
    responsibility = models.OneToOneField(Responsibility, on_delete=models.CASCADE, unique=True, verbose_name='Verantwortlichkeit')
    traffic_light = models.CharField(max_length=4, choices=COLORS, default='Grün', verbose_name='Ampel')
    created_at = models.DateTimeField(auto_now_add=True, editable=False, blank=True, verbose_name='Erstelldatum')
    updated_at = models.DateTimeField(auto_now=True, editable=False, blank=True, verbose_name='Änderungsdatum')

    class Meta:
        verbose_name = 'Status'
        verbose_name_plural = 'Status'

    def __str__(self):
        return f'{self.responsibility} | {self.traffic_light}'

filters.py

import django_filters
from .models import Responsibility


class ResponsibilityFilter(django_filters.FilterSet):
    class Meta:
        model = Responsibility
        fields = ['project', 'system', 'team', 'employee']

I also want to be able to filter by the traffic_light from the status model.

My second question: how can I filter multiple values? At the moment, I can only filter a single record. Here I use the filter in the template.

        <div class="card-body bg-light">
            <form method="GET">
                <div class="row">
                    {% for field in responsibilities_filter.form %}
                        <div class="col fw-bold">
                            {{ field.label_tag }}
                            {% render_field field class="form-control form-control" %}
                        </div>
                    {% endfor %}
                    <div class="col align-self-end">
                        <button class="btn btn-primary text-white" type="submit">Filtern <i class="fa fa-filter"></i></button>
                        <a href="{% url 'responsibilities' %}" class="btn btn-danger">Zurücksetzen <i class="fa fa-times-circle"></i></a>     
                    </div>  
                </div>
            </form>
        </div>

views.py

from django.shortcuts import render, get_object_or_404
from .models import Responsibility, BottleneckPart, Drawing, Meeting, Phase, Input, Output
from .filters import ResponsibilityFilter


# Create your views here.
def responsibilities_overview(request):
    responsibilities = Responsibility.objects.all()
    responsibilities_filter = ResponsibilityFilter(request.GET, queryset=responsibilities)
    responsibilities = responsibilities_filter.qs
    context = {'responsibilities': responsibilities, 'responsibilities_filter': responsibilities_filter}
    return render(request, 'systemcockpit/responsibilities_overview.html', context)

Best regards
Patrick

See: Filter Reference - django-filter 24.3 documentation

I’m not sure I’m clear on what you’re trying to do.

What I think you’re saying is that you want to supply multiple search terms to the filter. But then are you trying to retrieve all rows that match any one of the values, or all rows that match all values, or something else?

Either way, I think you’re going to need to build a custom filter - see FilterSet Options - django-filter 24.3 documentation. You’re probably also going to need to do some “preprocessing” of the search term entered into the search box - such as splitting the field by commas - to be able to build your composite search.

Hi Ken,

I currently have 4 fields to filter. When I click on one of them, a dropdown opens with all the available values. There I can only select a single value, but I would like to be able to select several.

Regarding the first question: What should the code look like for this? Just like that?

class ResponsibilityFilter(django_filters.FilterSet):
    class Meta:
        model = Responsibility
        fields = ['project', 'system', 'team', 'employee', 'responsibility.status.traffic_light']

Best regards
Patrick

What do the docs tell you to use?

Then you have two issues to address. First, you would need to change the form widget from being a select to being a select with the multiple attribute. Then you still need to modify the view as described above to handle those multiple selections.