Search code examples
djangodjango-rest-frameworkdjango-filter

How to filter in a django mptt-model using django-filters


I have models.py

from mptt.models import MPTTModel, TreeForeignKey

class Category(MPTTModel):
    name = models.CharField(max_length = 255, null = False, blank = False)
    parent = TreeForeignKey('self', on_delete = models.CASCADE, blank = False, null = True, related_name = 'children')
    # other fields

class Product(models.Model):
    category = models.ForeignKey(Category, on_delete = models.SET_NULL, null = True, blank = True, related_name = 'products')
    # other fields
    

views.py

class ProductAPIView(generics.GenericAPIView):

    serializer_class = ProductSerializer
    queryset = Product.objects.all()
    filter_backends = [ DjangoFilterBackend ]
    filterset_class = ProductFilter

    def get(self, request):
        products = self.filter_queryset(self.get_queryset())
        serializer = self.serializer_class(products, many = True)
        return Response(serializer.data)

class CategoryAPIView(generics.GenericAPIView):

    serializer_class = CategorySerializer
    queryset = Category.objects.root_nodes()

filters.py

from django_filters import FilterSet, CharFilter, NumberFilter
from .models import Product

class ProductFilter(FilterSet):
    brand = CharFilter(field_name='brand__name', lookup_expr='iexact')
    category = CharFilter(field_name='category__name', lookup_expr='iexact')
    discount = NumberFilter(field_name='discount', lookup_expr='gte')

    class Meta:
        model = Product
        fields = {}

My categories queryset response looks like this

{
   "name" : "electronics"
   "parent" : None,
   "products" : []
   "children" : [
       "name" : "cameras"
       "parent" : "electronics",
       "products" : []
       "children" : [
            "name": "DSLR Cameras",
            "parent" : "cameras",
            "products": [ "name": "Cannon EOS 80D DSLR Camera" ]
       ]
   ]
}

When i send query param with category=dslr cameras, i'm able to get the products associated with this category, but if i send a parent category name like category=electronics or category=cameras, I'd want to deep search the Category model to show products if the children also have these products. How can i achieve this?


Solution

  • Try this out:

    class ProductFilter(FilterSet):
        brand = CharFilter(field_name='brand__name', lookup_expr='iexact')
        category = CharFilter(method='filter_category_name')
        discount = NumberFilter(field_name='discount', lookup_expr='gte')
    
        class Meta:
            model = Product
            fields = {}
    
        def filter_category_name(self, queryset, name, value):
            return queryset.filter(category__in=Category.objects.filter(name__iexact=value).get_descendants(include_self=True))