Search code examples
djangodjango-modelsdjango-rest-frameworkdjango-filter

Django-filters how to use BooleanFilter to range or else


Good day, a question about "django-filters", "rest framework"

How to make a filter to
-1 option took up to 50% (in the decimal model),
-2 option after 50%,
-3 option equal 50

I did it with Boolean Filter and an additional "method" function - two fields, if true, then output the corresponding queryset. However, they are tied through one field and, accordingly, use one queryset, which makes them mutually exclusive when called at the same time, and not complementary as I need. I'm still looking at "ChoiceField", but I don't know if it's possible.

p.s. I tried to unite use union method in functions but get error "ORDER BY not allowed in subqueries of compound statements."

MY code from filter class:

class ProductsFilter(filters.FilterSet):
    type_one = filters.BooleanFilter(field_name='percentage_field', method='filter_one')
    type_two = filters.BooleanFilter(field_name='percentage_field',  method='filter_two')
    type_half = filters.BooleanFilter(field_name='percentage_field', method='filter_half')

    def filter_one(self, queryset, name, value):
        if value is True:
            return queryset.filter(percentage_field__range=(50.1, 100))
        else:
            return queryset

    def filter_two(self, queryset, name, value):
        if value is True:
            return queryset.filter(percentage_field__range=(0, 49.9))
        else:
            return queryset
    def filter_half(self, queryset, name, value):
        if value is True:
            asd = queryset
            return Product.objects.filter(percentage_field=50)
        else:
            return queryset

    class Meta:
        model = Product
        fields = ['name','price']

Filtering by one and by several at once filters, combining queryset and not exclude each other


Solution

  • Following answers

    1. https://stackoverflow.com/a/77374474/21259369 and
    2. https://stackoverflow.com/a/852481/21259369

    I used Multiple Choice Filter and query union Q() with a trick here "queries_set |= query" and i got multiple combined and single selection.

    from django.db.models import Q
    
    from django_filters import rest_framework as filters
    
    from apps.products.models import Product
    
    
    class ProductsFilter(filters.FilterSet):
    
        percentage_field = filters.MultipleChoiceFilter(
            choices=[
                ("bef50", "<50"),
                ("eq50", "50"),
                ("aft50", ">50"),
            ],
            method="filter_percentage_field",
            label="Choose percentage"
        )
    
        def filter_percentage_field(self, queryset, name, values):
            request = []
            for value in values:
                if value == "bef50":
                    request.append(Q(percentage_field__gt=50))
                elif value == "eq50":
                    request.append(Q(percentage_field=50))
                elif value == "aft50":
                    request.append(Q(percentage_field__lt=50))
    
            queries_set = request.pop()
            for query in request:
                queries_set |= query
    
            return queryset.filter(queries_set)
    
        class Meta:
            model = Product
            fields = ['percentage_field']