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())