Search code examples
djangodjango-modelsdjango-viewsdjango-filters

Django_filters apply all chosen filter fields


Hej! :)

I want to filter my data before I do some calculations with it with an AND operator. The chosen filter fields should ALL be applied. I added some fields of the mode to the filter function and I can filter (e.g.) for the name and the year seperate. But not combined. If I try to filter for both name AND year at the same time I would just get the results from year.

In my model I got an M2M to another model in which the year is set:

# models.py

class Plant(models.Model):
    name = models.CharField(
        max_length=200
    )
    used_xducts = models.ManyToManyField(
        Xduct,
        through="UsedXduct",
        blank=True,
        related_name="used_in_plant"
    )


class UsedXduct(models.Model):
    plant = models.ForeignKey(
        Plant,
        on_delete=models.PROTECT,
        related_name="used_in_plant"
    )
    xduct = models.ForeignKey(
        Xduct,
        on_delete=models.PROTECT,
        related_name="xduct"
    )
    year = models.SmallIntegerField(
        validators=[validate_year],
        blank=True,
        null=True
    )


class Xduct(models.Model):
    code = models.CharField(
        max_length = 20,
        blank = True,
        null = True,
        unique = True
    )
    name_english = models.CharField(
        max_length = 200,
        blank = True,
        null = True,
        unique = True
    )
    description_english = models.TextField(
        max_length = 500,
        blank = True
    )
    explanation_english = models.TextField(
        max_length = 4000,
        blank = True
    )
# filters.py

class PlantsNameFilter(django_filters.FilterSet):
    name = ModelChoiceFilter(queryset=Plant.objects.all())
    year = django_filters.NumberFilter(method='year_filter', label='Year')

    class Meta:
        model = Plant
        fields =["name", "year"]

    def year_filter(self, queryset, name, value):
        return Plant.objects.filter(
            Q(used_in_plant__year=value)
        )

Does anyone have an idea on whats going wrong? I have a similar filter for something else and it's working fine. I seem to miss something important.

Any help is appreciated! Thanks for the time :)


Solution

  • I think you need to use the queryset in the method year_filter of your filter. Currently you create a fresh queryset from scratch if the year-filter is applied. Replace Plant.objects with queryset like below:

    class PlantsNameFilter(django_filters.FilterSet):
        name = ModelChoiceFilter(queryset=Plant.objects.all())
        year = django_filters.NumberFilter(method='year_filter', label='Year')
    
        class Meta:
            model = Plant
            fields =["name", "year"]
    
        def year_filter(self, queryset, name, value):
            return queryset.filter( # <---- HERE
                Q(used_in_plant__year=value)
            )