Django - Объединение после фильтрации

Представьте, что есть модель и представление:

class Task(models.Model):
    title = models.CharField(...)
    message = models.TextField(...)
    performer = models.ForeignKey(User, on_delete=models.CASCADE, ...)
    orgunit = models.ForeignKey(OrgUnit, on_delete=models.CASCADE ...)
    deviation = models.ForeignKey(Deviation, on_delete=models.CASCADE, related_name='tasks', ...)
    creator = models.ForeignKey(User, on_delete=models.SET_NULL, ...)
    for_control = models.ManyToManyField('self', ...)
    # другие поля

class TasksViewSet(viewsets.ModelViewSet):
    serializer_class = TaskSerializer
    pagination_class = TasksPaginator
    filterset_class = TasksFilterSet

    def get_queryset(self):
        qs = Task.objects\
            .select_related(
                'performer__position__orgunit__conformation', 'deviation',
                'creator__position__orgunit__conformation', 'orgunit__conformation',
            ).prefetch_related('for_control')

        return qs

Поля в select_related и prefetch_related предназначены для будущей сериализации.

Насколько я знаю, сначала происходит объединение, а затем фильтрация (where clause from TasksFilterSet), верно? Если да, то очевидно, что это может повлиять на производительность.

Поэтому я подумал, не лучше ли сначала отфильтровать, а потом соединить? Конечно, некоторые соединения должны быть сделаны для фильтрации, но это не тот случай. Я имею в виду что-то вроде этого:

class TasksViewSet(viewsets.ModelViewSet):
    serializer_class = TaskSerializer
    pagination_class = TasksPaginator
    filterset_class = TasksFilterSet

    def get_queryset(self):
        return Task.objects.only('pk')

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        page = self.paginate_queryset(queryset)

        if page is not None:
            page = Task.objects.filter(pk__in=[task.pk for task in page]).select_related(
                'performer__position__orgunit__conformation', 'deviation',
                'creator__position__orgunit__conformation', 'orgunit__conformation',
            )
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

Что вы думаете об этом?

Порядок вызова select_related(), prefetch_related() и filter() не имеет значения. Результирующий набор запросов будет одинаковым

Из документации для select_related

Порядок следования цепочек filter() и select_related() не важен. Эти наборы запросов эквивалентны: Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog') Entry.objects.select_related('blog').filter(pub_date__gt=timezone.now())

Вернуться на верх