python-3.x Django rest如何序列化父注解下的所有子注解

lymnna71  于 2023-11-20  发布在  Python
关注(0)|答案(2)|浏览(119)

现在我的API响应如下所示

"results": [
        {
            "id": 12,
            "blog_slug": "rest-api-django",
            "comment": "Parent Comment",
            "main_comment_id": null
        },
        {
            "id": 13,
            "blog_slug": "rest-api-django",
            "comment": "Child Comment of 12",
            "main_comment_id": 12
        },
        {
            "id": 14,
            "blog_slug": "rest-api-django",
            "name": "Mr Ahmed",
            "comment": "Child Comment OF 13",
            "comment_uuid": "c0b389bc-3d4a-4bda-b6c6-8d3ef494c93c",
            "main_comment_id": 13
        }
    ]

字符串
我想要这样的东西

{
  "results": [
    {
      "id": 12,
      "blog_slug": "rest-api-django",
      "comment": "Parent Comment",
      "main_comment_id": null,
      "children": [
        {
          "id": 13,
          "blog_slug": "rest-api-django",
          "comment": "Child Comment of 12",
          "main_comment_id": 12,
          "children": [
            {
              "id": 14,
              "blog_slug": "rest-api-django",
              "name": "Mr Ahmed",
              "comment": "Child Comment OF 13",
              "comment_uuid": "c0b389bc-3d4a-4bda-b6c6-8d3ef494c93c",
              "main_comment_id": 13
            }
          ]
        }
      ]
    }
  ]
}


所以每个孩子都在父母之下,这是我模式

class BlogComment(models.Model):
      user  =  models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,blank=True,null=True)
      blog_slug = models.CharField(max_length=500)
      main_comment_id = models.ForeignKey("self",on_delete=models.CASCADE,blank=True,null=True)
      name = models.CharField(max_length=250)
      email = models.CharField(max_length=250)
      comment =  models.TextField()
      is_published = models.BooleanField(True)
      comment_uuid =  models.CharField(max_length=250)


我的博客评论Serializers

class BlogCommentSerializers(serializers.Serializer):
      id =  serializers.IntegerField(read_only=True)
      comment_uuid  =  serializers.CharField(read_only=True)
      blog_slug = serializers.CharField(max_length=500)
      main_comment_id = serializers.CharField(required=False)
      name = serializers.CharField(max_length=250)
      email = serializers.CharField(max_length=250)
      comment = serializers.CharField(style={'base_template': 'textarea.html'},allow_blank=False,required=True)
      is_published = serializers.BooleanField(default=True)


      def to_representation(self, instance):
        data = {
            'id': instance.id,
            'blog_slug': instance.blog_slug,
            'name': instance.name,
            'email': instance.email,
            'comment': instance.comment,
            "comment_uuid": instance.comment_uuid, 
            "main_comment_id": instance.main_comment_id
            
            
        }
        
        if instance.main_comment_id:
            data['main_comment_id'] = instance.main_comment_id.id  # Change to the ID number
        
        return data


下面是我API函数

if request.method == 'GET':
         paginator = PageNumberPagination()
         paginator.page_size = 1
         blogs = Blog.objects.filter(is_approved=True).all()
         result_page = paginator.paginate_queryset(blogs, request)
         serializer = BlogSerialzers(result_page, many=True)
         paginated_response = paginator.get_paginated_response(serializer.data)
        
         if paginated_response.get('next'):
            paginated_response.data['next'] = paginated_response.get('next')
         if paginated_response.get('previous'):
            paginated_response.data['previous'] = paginated_response.get('previous')

         return paginated_response

twh00eeo

twh00eeo1#

设置关系的方式,可以使用SerializerMethodField

class BlogCommentSerializers(serializers.ModelSerializer):
    children = serializers.SerializerMethodField()

    class Meta:
        model = BlogComment
        fields = ['id', 'blog_slug', 'comment', 'main_comment_id', 'children']
    
    def get_children(self, obj):
        children = BlogComment.objects.filter(main_comment_id=obj.id)
        serializer = BlogCommentSerializers(children, many=True)
        return serializer.data

字符串

mhd8tkvw

mhd8tkvw2#

我使用这种类型的结构来嵌套注解。过滤列表API的parent__isnull=True很重要,否则,它将在响应中重复。
models.py

class Comment(BaseModel):
    ...
    parent = models.ForeignKey(
        to="self",
        on_delete=models.CASCADE,
        related_name="children",
        blank=True,
        null=True,
    )
    ...

字符串
serializers.py

class CommentSerializer(DynamicFieldsModelSerializer):
    user = serializers.HiddenField(default=serializers.CurrentUserDefault())
    children = serializers.SerializerMethodField()
    text = serializers.CharField(required=True)

    @extend_schema_field(OpenApiTypes.OBJECT)
    def get_children(self, instance: Comment):
        return CommentSerializer(
            instance.children.all(), many=True, read_only=True
        ).data

    class Meta:
        model = Comment
        fields = "__all__"


views.py

class CommentViewSet(ModelViewSet):
    serializer_class = CommentSerializer

    def get_queryset(self):
        queryset = Comment.objects.prefetch_related("children").all()

        if self.action == "list":
            queryset = queryset.filter(parent__isnull=True)

        return queryset


这里需要注意的一点是,序列化器将被递归地调用以处理所有嵌套的注解。

相关问题