При использовании/вызове метода, вычисляющего queryset в другом методе, происходит многократное обращение к базе данных
Я работаю над проектом DRF, чтобы изучить модели ContentType. Я создал модель поста и модель комментария(ContentType), а затем добавил комментарии к посту. Все работало хорошо, пока я не добавил django-debug-tool и не продублировал запросы.
У меня есть следующие вопросы:
- I've defined a method(children) and property(total_replies) on the comment model. Since total_replies just calling children method and count the size of queryset. Will it result in hitting the database two or more times in case I use the children method in some other methods or property?
- If the database is hitting multiple times, what solution two improve performance?
- After adding select_related the num of queries has been reduced drastically.
Before using select_related

После использования select_related
Хорошо ли использовать select_related во всех местах, где использовался Foreignkey?
Приложение к блогу
models.py
class Post(models.Model):
title = models.CharField(verbose_name=_("Post Title"), max_length=50)
content = models.TextField()
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='blog_posts')
category = models.ForeignKey(Category, on_delete=models.CASCADE)
def __str__(self):
return self.title
@property
def comments(self):
instance = self
#qs = Comment.objects.filter_by_instance(instance) #before
qs = Comment.objects.select_related('user').filter_by_instance(instance)
return qs
@property
def get_content_type(self):
instance = self
content_type = ContentType.objects.get_for_model(instance.__class__)
return content_type
serializers.py
class PostSerializer(serializers.ModelSerializer):
author = UserPublicSerializer(read_only=True)
status_description = serializers.ReadOnlyField(source='get_status_display')
class Meta:
model = Post
fields = (
'url', 'id', 'title', 'author',
'content', 'category', 'total_likes',
)
class PostDetailSerializer(serializers.ModelSerializer):
author = UserPublicSerializer(read_only=True)
status_description = serializers.ReadOnlyField(source='get_status_display')
comments = serializers.SerializerMethodField()
class Meta:
model = Post
fields = (
'url', 'id', 'title', 'author', 'content',
'category', 'comments', 'total_likes'
)
def get_comments(self, obj):
request = self.context.get('request')
comments_qs = Comment.objects.filter_by_instance(obj)
comments = CommentSerializer(comments_qs, many=True, context={'request':request}).data
return comments
class PostListCreateAPIView(generics.ListCreateAPIView):
serializer_class = serializers.PostSerializer
# queryset = Post.objects.all().order_by('-id') # before
queryset = Post.objects.select_related('author').order_by('-id')
name = 'post-list'
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
def perform_create(self, serializer):
serializer.save(author=self.request.user)
class PostRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
serializer_class = serializers.PostDetailSerializer
# queryset = Post.objects.all().order_by('-id') # before
queryset = Post.objects.select_related('author').order_by('-id')
name = 'post-detail'
permission_classes = [permissions.IsAuthenticatedOrReadOnly, account_permissions.IsStaffOrAuthorOrReadOnly]
def perform_update(self, serializer):
serializer.save(author=self.request.user)
Комментарий приложения
Заранее спасибо.
Это именно то, что говорится в документации django о select_related :
"Возвращает QuerySet, который будет "следовать" за отношениями "иностранный ключ", выбирая дополнительные данные связанных объектов при выполнении запроса. Это увеличение производительности, которое приводит к одному более сложному запросу, но означает, что последующее использование отношений "иностранный ключ" не потребует запросов к базе данных."
Они описывают select_related как нечто сложное, но хорошее с точки зрения транзакционной стоимости БД.