首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在另一个方法中使用/调用具有计算查询集的方法是否多次访问数据库?

在另一个方法中使用/调用具有计算查询集的方法是否多次访问数据库?
EN

Stack Overflow用户
提问于 2022-04-03 12:37:05
回答 1查看 21关注 0票数 0

我正在从事一个DRF项目,以了解ContentType模型。我创建了一个post模型和注释模型(ContentType),然后将评论添加到文章中。在我添加django-调试工具和重复查询之前,一切都很好。

我有以下问题:

  1. 我在注释模型上定义了一个方法(子)和属性(Total_replies)。因为total_replies只是调用子方法并计算queryset的大小。如果我在其他方法或属性中使用子方法,它会导致访问数据库两次或更多次吗?
  2. 如果数据库多次命中,什么解决方案二可以提高性能?
  3. 在添加select_related之后,查询的num大大减少了。在使用select_related之前

使用select_related后

在所有使用Foreignkey的地方使用select_related好吗?

博客应用程序

代码语言:javascript
运行
复制
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)

评论应用程序

代码语言:javascript
运行
复制
models.py

class CommentManager(models.Manager):
    def all(self):
        qs = super().filter(parent=None)
        return qs

    def filter_by_instance(self, instance):
        content_type = ContentType.objects.get_for_model(instance.__class__)
        object_id = instance.id
        qs = super().filter(content_type=content_type, object_id=object_id).select_related('user').filter(parent=None)
        return qs


class Comment(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='comments')
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey(ct_field='content_type', fk_field='object_id')
    parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE)
    content = models.TextField()
   
    objects = CommentManager()

    def __str__(self):
        if self.is_parent:
            return f"comment {self.id} by {self.user}"
        return f"reply {self.id} to comment {self.parent.id} by {self.user}"

    def children(self):
        return Comment.objects.select_related('user').filter(parent=self)

    @property
    def is_parent(self):
        if self.parent is not None:
            return False
        return True

    @property
    def total_replies(self):
        return self.children().count()


serializers.py

class CommentSerializer(serializers.ModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name='comment-detail', lookup_field='pk')
    user = UserPublicSerializer(read_only=True)

    class Meta:
        model = Comment
        fields = ('url', 'user', 'id', 'content_type', 'object_id', 'parent', 'content',  'total_replies',)


class CommentChildSerializer(serializers.ModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name='comment-detail', lookup_field='pk')
    user = UserPublicSerializer(read_only=True)

    class Meta:
        model = Comment
        fields = ('url', 'user',  'id', 'content',)


class CommentDetailSerializer(serializers.ModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name='comment-detail', lookup_field='pk')
    replies = serializers.SerializerMethodField()

    class Meta:
        model = Comment
        fields = ('url', 'id', 'content_type', 'object_id', 'content', 'replies', 'total_replies',)

    def get_replies(self, obj):
        request = self.context.get('request')
        if obj.is_parent:
            return CommentChildSerializer(obj.children(), many=True, context={'request':request}).data
        return None


views.py

class CommentListAPIView(generics.ListCreateAPIView):
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    queryset = Comment.objects.select_related('user').order_by('-id')
    name = 'comment-list'
    serializer_class = serializers.CommentSerializer

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)

class CommentDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    queryset = Comment.objects.select_related('user').all()
    name = 'comment-detail'
    serializer_class = serializers.CommentDetailSerializer

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)

提前谢谢。

EN

回答 1

Stack Overflow用户

发布于 2022-04-03 14:10:40

django博士正是这么说相关的:

返回一个将“跟踪”外键关系的QuerySet,在执行其查询时选择附加的相关对象数据。--这是一个性能提升器,会产生一个更复杂的查询,但意味着以后使用外键关系将不需要数据库查询。

他们将select_related描述为复杂但在事务性数据库成本方面很好的东西。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71725965

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档