簡體   English   中英

DRF-編寫雙嵌套序列化器的更好方法

[英]DRF - a better way to write double nested serializers

我正在構建一個待辦事項應用程序,可以在待辦事項上發布評論。 為此,我制作了一個可寫的雙嵌套序列化器。 它可以工作,但是我編寫的更新方法很難理解,因此我試圖使其更具可讀性。 是否有更好(或標准的方式)為雙嵌套序列化器編寫更新方法?

我已經閱讀了官方文檔中有關嵌套序列化程序的文檔。 https://www.django-rest-framework.org/api-guide/serializers/

models.py

class CustomUser(AbstractUser):

    def __str__(self):
        return self.email


class Todo(models.Model):
    publisher = models.ForeignKey(
        CustomUser,
        on_delete=models.CASCADE,
        related_name="todos",
    )
    title = models.CharField(max_length=50)
    pub_date = models.DateTimeField('date published')
    description = models.CharField(max_length=800)
    is_done = models.BooleanField(default=False)

    def __str__(self):
        return self.title


class Comment(models.Model):
    subject = models.ForeignKey(
        Todo,
        on_delete=models.CASCADE,
        related_name="comments",
    )
    publisher = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
    title = models.CharField(max_length=50, default=None)
    pub_date = models.DateTimeField('date published')
    description = models.CharField(max_length=800)

    def __str__(self):
        return self.description

serializers.py

class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = (
            'url',
            'title',
            'pub_date',
            'description',
        )
        read_only_fields = (
            'url',
            'pub_date',
        )


class TodoSerializer(serializers.ModelSerializer):
    comments = CommentSerializer(required=False, many=True)

    class Meta:
        model = Todo
        fields = (
            'url',
            'title',
            'pub_date',
            'description',
            'is_done',
            'comments'
        )
        read_only_fields = (
            'url',
            'pub_date',
        )


class UserSerializer(serializers.ModelSerializer):
    todos = TodoSerializer(required=False, many=True)

    class Meta:
        model = CustomUser
        fields = (
            'url',
            'email',
            'username',
            'todos',
        )
        read_only_fields = (
            'url',
            'email',
        )

    def create(self, validated_data):
        todos = validated_data.pop('todos', None)
        user = CustomUser.objects.create(**validated_data)

        if todos is not None:
            for todo in todos:
                comments = todo.pop('comments', None)
                Todo.objects.create(user=user, **todo)
                if comments is not None:
                    for comment in comments:
                        Comment.objects.create(todo=todo, **comment)
        return user

    def update(self, instance, validated_data):
        todos_data = validated_data.pop('todos', None)
        todos = (instance.todos).all()
        todos = list(todos)
        instance.username = validated_data.get('username', instance.username)
        instance.save()
        if todos_data is not None:
            for todo_data in todos_data:
                comments_data = todo_data.pop('comments')
                todo = todos.pop(0)
                comments = (todo.comments).all()
                comments = list(comments)

                todo.title = todo_data.get('title', todo.title)
                todo.description = todo_data.get('description', todo.description)
                todo.is_done = todo_data.get('is_done', todo.is_done)
                todo.save()
                if comments_data is not None:
                    for comment_data in comments_data:
                        comment = comments.pop(0)
                        comment.title = comment_data.get('title', comment.title)
                        comment.description = comment_data.get('description', comment.description)
                        comment.save()
        return instance

預期的JSON

{
    "url": "http://127.0.0.1:8000/api/users/4/",
    "email": "api01@example.com",
    "username": "api01",
    "todos": [
        {
            "url": "http://127.0.0.1:8000/api/todo/1/",
            "title": "first todo1.1",
            "pub_date": "2019-07-04T12:40:56.799308+09:00",
            "description": "description for first todo1.1",
            "is_done": true,
            "comments": [
                {
                    "url": "http://127.0.0.1:8000/api/comment/1/",
                    "title": "first comment-1.1",
                    "pub_date": "2019-07-03T12:32:26.604598+09:00",
                    "description": "aaaaaaaaa-1.1"
                },
                {
                    "url": "http://127.0.0.1:8000/api/comment/2/",
                    "title": "second comment-1.1",
                    "pub_date": "2019-07-03T12:56:22.906482+09:00",
                    "description": "bbbbbbbbbbb-1.1"
                }
            ]
        }
    ]
}

創建模型應該是各個序列化程序的責任。 因此TodoSerializer應該只創建Todo對象, CommentSerializer應該創建Comment對象。 相同的更新

另外,您不需要調用Model.objects.create(**data) 序列化程序可以自己完成。 您只需要調用super().create(validated_data)super().update(instance, validated_data)

class TodoSerializer(serializers.ModelSerializer):

    comments = serializers.ListField(child=serializers.DictField, required=True)

    class Meta:
        model = CustomUser
        fields = (
            'title',
            'pub_date',
            'description',
            'is_done',
            'comment',
        )

    def create(self, validated_data)
        todo = super().create(validated_data)
        comments = validated_data.pop('comments', [])
        for comment in comments:
            comment['todo'] = todo.id
            serializer = CommentSerializer(data=comment)
            serializer.is_valid(raise_exception=True)
            serializer.save()


class AddBulkTodos(serializers.ModelSerializer):
    todos = serializers.ListField(child=serializers.DictField, required=True)

    class Meta:
        model = CustomUser
        fields = (
            'url',
            'email',
            'username',
            'todos',
        )
        read_only_fields = (
            'url',
        )

    def create(self, validated_data)
        todos = validated_data.pop('todos', [])
        user = super().create(validated_data)
        for todo in todos:
            todo['user'] = user.id
            serializer = TodoSerializer(data=todo)
            serializer.is_valid(raise_exception=True)
            serializer.save()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM