django - DRF Serializer 更新嵌套对象列表
问题描述
我使用 Django-rest-framework 编写投票应用程序项目。它有两种模型:问题和嵌套答案。我想根据要求更新问题序列化程序的答案,例如:
{
"question":"question",
"answers": [{"answer":"first updated answer"}, {"answer":"second update answer"}]
}
我怎样才能正确地做到这一点?我尝试这样做,但是我删除了每个请求中的答案并创建了新的答案,因为每次都会更改他们的 ID。
序列化程序.py
class QuestionSerializer(serializers.ModelSerializer):
user = serializers.StringRelatedField()
answers = AnswerSerializer(many=True)
class Meta(object):
model = Question
fields = ('id', 'question', 'answers', 'total_votes', 'user')
read_only_fields = ('id', 'total_votes', )
def update(self, instance, validated_data):
instance.question = validated_data.get('question', instance.question)
instance.save()
question = Question.objects.get(id=instance.id)
Answer.objects.filter(question=question).delete()
answers_data = validated_data.pop('answers')
for answer_data in answers_data:
Answer.objects.create(question=question, **answer_data)
return instance
模型.py
class Question(models.Model):
question = models.CharField(verbose_name='Question', max_length=255)
total_votes = models.IntegerField(verbose_name='Total Votes', default=0)
user = models.ForeignKey(User, verbose_name='Owner', on_delete=models.CASCADE)
class Answer(models.Model):
question = models.ForeignKey(Question, verbose_name='Question', related_name='answers',
on_delete=models.CASCADE)
answer = models.CharField(verbose_name='Answer', blank=True, max_length=255)
votes_count = models.IntegerField(verbose_name='Count of Votes', default=0)
解决方案
经过数小时的文档冲浪后才想到这一点:
序列化程序.py
class AnswerSerializer(serializers.ModelSerializer):
# this is IMPORTANT, without this the 'id' field won't appear in validated data
id = serializers.IntegerField(required=False, write_only=False)
class Meta:
model = Answer
class QuestionSerializer(serializers.ModelSerializer):
user = serializers.StringRelatedField()
answers = AnswerSerializer(many=True)
def update(self, instance, validated_data):
answer_data = validated_data.pop("answers")
remove_items = { item.id: item for item in instance.answers.all() }
for item in answer_data:
item_id = item.get("id", None)
if item_id is None:
# new item so create this
instance.answers.create(**item)
elif remove_items.get(item_id, None) is not None:
# update this item
instance_item = remove_items.pop(item_id)
Answer.objects.filter(id=instance_item.id).update(**item)
for item in remove_items.values():
item.delete()
for field in validated_data:
setattr(instance, field, validated_data.get(field, getattr(instance, field)))
instance.save()
return instance
推荐阅读
- reactjs - 获取 API - 数据值
- amazon-web-services - 为每个客户提供单独 AWS RDS 实例的好处
- jmeter - 如果字符串在来自 http 请求 JMeter 的 JSON 响应中,如何断言失败
- python-3.x - 获取python + flask中子文件夹中图像的完整路径
- python - 我如何在 python 中绘制训练结果
- c# - Excel 总是返回日期格式 dd-MM-yy 而不是 dd-MM-yyyy
- java - 如何从java中的递归方法返回null
- microservices - 我应该在微服务之间共享我的库吗?
- react-native - TypeError:无法读取主 App.js 文件中未定义的属性“导航”
- java - 带有 JSON 主体的 POST 请求不会传递到 springboot 微服务架构中的端点