我正在构建一个待办事项应用程序,可以在待办事项上发布评论。 为此,我制作了一个可写的双嵌套序列化器。它可以工作,但是我编写的更新方法很难理解,因此我试图使其更具可读性。是否有更好(或标准的方式)为双嵌套序列化器编写更新方法?
我已经阅读了官方文档中有关嵌套序列化程序的文档。 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"
}
]
}
]
}
答案 0 :(得分:0)
创建模型应该由相应的序列化程序负责。因此,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()