【问题标题】:Django Rest API- use prefetch_related with ModelSerializerDjango Rest API - 将 prefetch_related 与 ModelSerializer 一起使用
【发布时间】:2021-02-11 12:10:42
【问题描述】:

每篇博文我都有一个评论栏。 我想将 Views.py 中的 Comment.objects.all() 传递给 ModelSerializer def get_cmets(self, obj) 以减少 sql 查询的数量。因为我正在序列化博客文章列表

Views.py

class BlogViewSet(ModelViewSet):
    queryset = Blog.objects.all().annotate(
        author_name=F('author__username')
    )
    serializer_class = BlogSerializer
    permission_classes = [IsOwnerOrReadOnly]

        def list(self, request):
            return Response({'blogs': BlogSerializer(self.queryset, many=True).data})

Serializers.py

class BlogSerializer(ModelSerializer):
    author_name = serializers.CharField(read_only=True)
    comments = SerializerMethodField()

    class Meta:
        model = Blog
        fields = ('title_text', 'main_text', 'datepublished', 'author_name', 'id', 'comments')


    def get_comments(self, obj):
        # filter comment
        comment_object = Comment.objects.filter(post_id=obj.id)
        comments = CommentSerializer(comment_object, many=True).data
        return comments

【问题讨论】:

    标签: python django django-rest-framework


    【解决方案1】:

    您不必从视图中传递任何内容。

    • 首先,您必须更改 BlogSerializer 中的 comments 字段。
    class CommentSerializer(ModelSerializer):
        # This serializer should have all the details of your comments.
        ....
        class Meta:
            model = Comment
            fields = "__all__" # Or whatever fields you want to set.
    
    class BlogSerializer(ModelSerializer):
        author_name = serializers.CharField(read_only=True)
        comments = CommentSerializer(many=True, read_only=True) # I am not sure of the source of your comment reverse manager name
    
        class Meta:
            model = Blog
            fields = ('title_text', 'main_text', 'datepublished', 'author_name', 'id', 'comments')
    
    • 其次,您必须对视图的查询集进行少量更改,以减少使用prefetch_related 发送到数据库的查询数量
    class BlogViewSet(ModelViewSet):
        queryset = Blog.objects.prefetch_related('comments').all().annotate(
            author_name=F('author__username')
        )
        serializer_class = BlogSerializer
        permission_classes = [IsOwnerOrReadOnly]
    
            def list(self, request):
                return Response({'blogs': BlogSerializer(self.get_queryset(), many=True).data})
    

    我在代码 sn-ps 中假设您没有为 Comment 模型在 Blog ForeignKey 上设置 related_name,因此默认情况下,Blog 上的相关管理器将是 @ 987654332@

    更新

    你的模型应该是这样的,为了让这个解决方案起作用

    class Comment(models.Model):
        ...
        blog = models.ForeignKey('Blog', on_delete=models.CASCADE, related_name='comments')
        ...
    
    class Blog(models.Model):
        # comment = models.ForeignKey(Comment, on_delete=models.CASCADE, null=True) 
        # this foreign key shouldn't be here, remove it.
    
        ....
    

    对 Serializer 和 View 进行更改

    # in BlogSerializer
        comments = CommentSerializer(many=True, read_only=True)
    # In BlogViewSet
        queryset = Blog.objects.prefetch_related('comments').all().annotate(
            author_name=F('author__username')
        )
    

    【讨论】:

    • 我在帖子的 ForeignKey 中添加了一个模型评论,没有 verbose_name,并按照你写的做了一切。但出现错误“无法在博客对象上找到 'comment_set','comment_set' 是 prefetch_related() 的无效参数”
    • 您能否发布您的models.py 文件,以查看您的模型之间的关系。
    • 这里快速说明一下,您在 Blog 模型中的外键,这意味着您的博客帖子将只有 1 条评论,这就是您希望您的博客帖子的样子吗?
    • 检查我答案中的更新部分,这些更改后它将起作用
    猜你喜欢
    • 2015-03-23
    • 2019-12-26
    • 2016-11-08
    • 2013-09-20
    • 2016-07-16
    • 1970-01-01
    • 2015-03-29
    • 2012-08-02
    • 2017-03-21
    相关资源
    最近更新 更多