【发布时间】:2019-11-16 14:51:03
【问题描述】:
我正在构建一个可以将 cmets 发布到 todo 的 todo 应用程序。 为此,我制作了一个可写的双嵌套序列化程序。它可以工作,但是我写的更新方法很难理解,所以我试图让它更具可读性。是否有更好的(或标准的方法)为双嵌套序列化程序编写更新方法?
我已阅读官方文档中有关嵌套序列化程序的文档。 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
序列化器.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"
}
]
}
]
}
【问题讨论】:
-
好吧,我不确定您希望如何使用它。所以你期望用户会同时创建他所有的 todo 并且每个 todo 在创建时已经有一堆 cmets?这与现实相去甚远。实际上,您今天分别创建每个,并且 cmets 逐渐添加到每个待办事项中。所以你的序列化器是不必要的复杂
-
哦.. 我想我误解了使用序列化程序的方式。我认为我必须将所有这些组合起来才能在一个页面中使用它们,例如当我想将来自特定用户的待办事项加载到页面上时,以及发布到待办事项上的 cmets。谢谢!
-
您始终可以发出多个请求来获取页面的数据。此外,您可以决定在同一请求中返回所有附加到它们的 todos 和 cmets,但单独创建它们。您可以阅读有关 read_only 和 write_only 字段
标签: python django django-rest-framework nested serialization