Search code examples
pythonpython-3.xdjangodjango-rest-frameworkdjango-filter

Django Many To Many table filter makes too many sql queries


I'm filtering my Department model with django_filters. But it makes too many queries. How can I fix it?

# models.py

class Branch(models.Model):
    name = models.CharField(max_length=100)

    class Meta:
        verbose_name_plural = "Branches"

    def __str__(self):
        return self.name


class Department(models.Model):
    name = models.CharField(max_length=100)
    branch = models.ManyToManyField(Branch, related_name="department")

    def __str__(self):
        return self.name

_

# views.py

class DepartmentListAPIView(generics.ListAPIView):
    queryset = Department.objects.all()
    serializer_class = DepartmentSerializer
    filter_backends = (filters.DjangoFilterBackend,)
    filterset_class = DepartmentFilter

_

# serializers.py

class DepartmentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Department
        fields = "__all__"

_

# filters.py

class DepartmentFilter(filters.FilterSet):
    branch = filters.CharFilter(field_name="branch__id", lookup_expr="in")

    class Meta:
        model = Department
        fields = "__all__"

Screen of django_toolbar

enter image description here


Solution

  • This has nothing to do with filtering, but with serializing: your serializer forces to fetch the related Branches for each Department individually, you can fetch these all in one extra query with:

    class DepartmentListAPIView(generics.ListAPIView):
        queryset = Department.objects.prefetch_related('branch')
        serializer_class = DepartmentSerializer
        filter_backends = (filters.DjangoFilterBackend,)
        filterset_class = DepartmentFilter

    Note: Since a ManyToManyField refers to a collection of elements, ManyToManyFields are normally given a plural name. You thus might want to consider renaming branch to branches.