carltongibson / django-filter

A generic system for filtering Django QuerySets based on user selections
https://django-filter.readthedocs.io/en/main/
Other
4.44k stars 767 forks source link

dynamic filter remembered during next api calls #1663

Open MehdiDRISSIB opened 4 months ago

MehdiDRISSIB commented 4 months ago

Hello

I created dynamic filters in my filterset like this:

class ProductFilter(FilterSet):
    price = django_filters.NumericRangeFilter(field_name="inventory__default_price", lookup_expr='lt', label=_('price'),
                                              method='get_product_price_range')
    inspiration_country = django_filters.MultipleChoiceFilter(choices=countries, field_name=_("Inspiration country"),
                                                              lookup_expr='in', method='get_inspiration_countries',
                                                              label=_('inspiration country'))
    category_hierarchy = django_filters.ChoiceFilter(method='get_category_hierarchy', label=_('Category'))
    ...

    class Meta:
        model = Product
        fields = ['price', "inspiration_country", 'translations__slug', 'category_hierarchy',
                  'in_promo', 'customizable']

    def __init__(self, *args, **kwargs):
        super(ProductFilter, self).__init__(*args, **kwargs)
        cat = None
        if 'search' in self.data and self.data.get('search') and not ('category_hierarchy' in self.data and self.data.get('category_hierarchy')):
            cat = self.get_category_from_search(self.data.get('search'))
        elif 'category_hierarchy' in self.data and self.data.get('category_hierarchy'):
            cat = self.get_category_from_slug_hierarchy(self.data.get('category_hierarchy'))

        if cat:
            ...
            attributes = Attribute.objects.prefetch_related('choices').filter(categories__in=cat.get_ancestors(include_self=True))
            for attr in attributes:
                if attr.is_stringy:
                    self.base_filters[attr.name] = django_filters.MultipleChoiceFilter(
                        method='get_attribute_choice',
                        choices=[(choice.id, choice) for choice in attr.choices.all()],
                        label=attr.name
                    )
                    self.base_filters[attr.name].field_name = attr.name
                elif attr.is_boolean:
                    self.base_filters[attr.name] = django_filters.BooleanFilter(
                        method='get_attribute_boolean',
                        label=attr.name
                    )
                    self.base_filters[attr.name].field_name = attr.name
         ...

As you can see depending of the category. I request the attributes of a category. Then I assign to self.base_filters new filters. The issue is that during the first call: https://noodra.com:8443/api/product/product/?category_hierarchy=grocery-and-crus : the result is correct on the second call: https://noodra.com:8443/api/product/product/?category_hierarchy=clothing-and-shoes : the result of filters is wrong because self.base_filters come and remember the filters of grocery-and-crus. So in this second call, I got filters calculated from the grocery-and-crus and from this clothing-and-shoes

for example, on clothing and shoes, I will get one new filter color. in the second call, I should have some other filters related to grocery but I got color filter also with my grocery filters.

Many thanks for your answer