使用 DRF 嵌套 fields/objects 创建
Nested fields/objects creation with DRF
又是我来问关于民意调查的问题API我正在处理。
我有三个模型:投票、问题和选择。
from django.db import models
from django.contrib.auth import get_user_model
User = get_user_model()
class Poll(models.Model):
title = models.CharField(max_length=200, verbose_name="Naslov ankete")
description = models.TextField(verbose_name="Opis ankete")
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="polls", verbose_name="Autor")
pub_date = models.DateTimeField(auto_now_add=True, verbose_name="Datum objavljivanja")
class Meta:
ordering = ["pub_date", "title"]
verbose_name = "Anketa"
verbose_name_plural = "Ankete"
def __str__(self):
return self.title
class Question(models.Model):
poll = models.ForeignKey(Poll, on_delete=models.CASCADE, related_name="questions", verbose_name="Anketa")
question_text = models.CharField(max_length=200, verbose_name="Tekst pitanja")
class Meta:
# ordering = ["question_text"]
verbose_name = "Pitanje"
verbose_name_plural = "Pitanja"
def __str__(self):
return self.question_text
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name="choices", verbose_name="Pitanje")
choice_text = models.CharField(max_length=200, verbose_name="Tekst opcije")
votes = models.IntegerField(default=0, verbose_name="Glasovi")
class Meta:
# ordering = ["-votes"]
verbose_name = "Opcija"
verbose_name_plural = "Opcije"
def __str__(self):
return self.choice_text
无论我在序列化程序中放入什么,我都无法实现与投票同时创建问题和选择。注意:问题和选择不是必填字段(可以创建没有问题的投票并稍后添加,也可以创建没有选择的问题并稍后添加)。
如果我想使用以下 JSON 但仍然能够独立创建问题和选择,我的序列化程序应该是什么样子?
{
"title": "Favorite destinations",
"description": "A few questions about traveling",
"questions": [
{"question_text": "Which destination seems better for you?", "choices": [{"choice_text": "London"}, {"choice_text": "Madrid"}, {"choice_text": "Rome"}, {"choice_text": "Paris"}, {"choice_text": "Berlin"}]},
{"question_text": "When was the most recent occasion you travelled abroad?", "choices": [{"choice_text": "this month"}, {"choice_text": "less than three months ago"}, {"choice_text": "in the last six months"}, {"choice_text": "last year"}, {"choice_text": "in the last three years"}, {"choice_text": "I don't remember"}]},
{"question_text": "Where of those would you rather travel?", "choices": [{"choice_text": "sea"}, {"choice_text": "mountains"}, {"choice_text": "desert"}, {"choice_text": "volcano"}]}
]
}
你必须这样使用 Nested Serializers :
class ChoiceSerializer(serializers.ModelSerializer):
class Meta:
model = Choice
fields = "__all__"
class QuestionSerializer(serializers.ModelSerializer):
choices = ChoiceSerializer(many=True)
class Meta:
model = Question
fields = "__all__"
class PollSerializer(serializers.ModelSerializer):
questions = QuestionSerializer(many=True)
class Meta:
model = Poll
fields = "__all__"
def create(self, validated_data):
questions_data = validated_data.pop('questions')
poll = Poll.objects.create(**validated_data)
for question_data in questions_data:
choices_data = question_data.pop('choices')
question = Question.objects.create(poll=poll, **question_data)
for choice_data in choices_data:
choices = Choice.objects.create(question=question, **choice_data)
return poll
对于好奇的人,这里是通过自定义 Reza 的答案创建的代码。
serializers.py
from rest_framework import serializers
from .models import Poll, Question, Choice
class ChoiceSerializer(serializers.ModelSerializer):
class Meta:
model = Choice
fields = ["id", "choice_text"]
class QuestionSerializer(serializers.ModelSerializer):
choices = ChoiceSerializer(many=True, required=False)
class Meta:
model = Question
fields = ["id", "question_text", "choices"]
def create(self, validated_data):
if "choices" in validated_data:
choices_data = validated_data.pop("choices")
question = Question.objects.create(**validated_data)
for choice_data in choices_data:
choice = Choice.objects.create(question=question, **choice_data)
return question
return Question.objects.create(**validated_data)
class PollSerializer(serializers.ModelSerializer):
author = serializers.HiddenField(default=serializers.CurrentUserDefault())
questions = QuestionSerializer(many=True, required=False)
class Meta:
model = Poll
fields = "__all__"
def create(self, validated_data):
if "questions" in validated_data:
questions_data = validated_data.pop("questions")
poll = Poll.objects.create(**validated_data)
for question_data in questions_data:
if "choices" in question_data:
choices_data = question_data.pop("choices")
question = Question.objects.create(poll=poll, **question_data)
for choice_data in choices_data:
choice = Choice.objects.create(question=question, **choice_data)
return poll
return Poll.objects.create(**validated_data)
class VoteSerializer(serializers.ModelSerializer):
class Meta:
model = Choice
fields = ["votes"]
def update(self, instance, validated_data):
instance.votes += 1
instance.save()
return instance
class ChoiceWithVotesSerializer(serializers.ModelSerializer):
class Meta:
model = Choice
fields = "__all__"
class QuestionWithVotesSerializer(serializers.ModelSerializer):
choices = ChoiceWithVotesSerializer(many=True, required=False)
class Meta:
model = Question
fields = "__all__"
class PollDetailsSerializer(serializers.ModelSerializer):
questions = QuestionWithVotesSerializer(many=True)
class Meta:
model = Poll
fields = "__all__"
还有显示投票的序列化程序,在具有自定义 IsPollAuthor 权限的视图中使用 - 仅供投票作者使用。当然,还有一个允许对经过身份验证的用户进行投票的序列化程序。 :)
又是我来问关于民意调查的问题API我正在处理。
我有三个模型:投票、问题和选择。
from django.db import models
from django.contrib.auth import get_user_model
User = get_user_model()
class Poll(models.Model):
title = models.CharField(max_length=200, verbose_name="Naslov ankete")
description = models.TextField(verbose_name="Opis ankete")
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="polls", verbose_name="Autor")
pub_date = models.DateTimeField(auto_now_add=True, verbose_name="Datum objavljivanja")
class Meta:
ordering = ["pub_date", "title"]
verbose_name = "Anketa"
verbose_name_plural = "Ankete"
def __str__(self):
return self.title
class Question(models.Model):
poll = models.ForeignKey(Poll, on_delete=models.CASCADE, related_name="questions", verbose_name="Anketa")
question_text = models.CharField(max_length=200, verbose_name="Tekst pitanja")
class Meta:
# ordering = ["question_text"]
verbose_name = "Pitanje"
verbose_name_plural = "Pitanja"
def __str__(self):
return self.question_text
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name="choices", verbose_name="Pitanje")
choice_text = models.CharField(max_length=200, verbose_name="Tekst opcije")
votes = models.IntegerField(default=0, verbose_name="Glasovi")
class Meta:
# ordering = ["-votes"]
verbose_name = "Opcija"
verbose_name_plural = "Opcije"
def __str__(self):
return self.choice_text
无论我在序列化程序中放入什么,我都无法实现与投票同时创建问题和选择。注意:问题和选择不是必填字段(可以创建没有问题的投票并稍后添加,也可以创建没有选择的问题并稍后添加)。
如果我想使用以下 JSON 但仍然能够独立创建问题和选择,我的序列化程序应该是什么样子?
{
"title": "Favorite destinations",
"description": "A few questions about traveling",
"questions": [
{"question_text": "Which destination seems better for you?", "choices": [{"choice_text": "London"}, {"choice_text": "Madrid"}, {"choice_text": "Rome"}, {"choice_text": "Paris"}, {"choice_text": "Berlin"}]},
{"question_text": "When was the most recent occasion you travelled abroad?", "choices": [{"choice_text": "this month"}, {"choice_text": "less than three months ago"}, {"choice_text": "in the last six months"}, {"choice_text": "last year"}, {"choice_text": "in the last three years"}, {"choice_text": "I don't remember"}]},
{"question_text": "Where of those would you rather travel?", "choices": [{"choice_text": "sea"}, {"choice_text": "mountains"}, {"choice_text": "desert"}, {"choice_text": "volcano"}]}
]
}
你必须这样使用 Nested Serializers :
class ChoiceSerializer(serializers.ModelSerializer):
class Meta:
model = Choice
fields = "__all__"
class QuestionSerializer(serializers.ModelSerializer):
choices = ChoiceSerializer(many=True)
class Meta:
model = Question
fields = "__all__"
class PollSerializer(serializers.ModelSerializer):
questions = QuestionSerializer(many=True)
class Meta:
model = Poll
fields = "__all__"
def create(self, validated_data):
questions_data = validated_data.pop('questions')
poll = Poll.objects.create(**validated_data)
for question_data in questions_data:
choices_data = question_data.pop('choices')
question = Question.objects.create(poll=poll, **question_data)
for choice_data in choices_data:
choices = Choice.objects.create(question=question, **choice_data)
return poll
对于好奇的人,这里是通过自定义 Reza 的答案创建的代码。
serializers.py
from rest_framework import serializers
from .models import Poll, Question, Choice
class ChoiceSerializer(serializers.ModelSerializer):
class Meta:
model = Choice
fields = ["id", "choice_text"]
class QuestionSerializer(serializers.ModelSerializer):
choices = ChoiceSerializer(many=True, required=False)
class Meta:
model = Question
fields = ["id", "question_text", "choices"]
def create(self, validated_data):
if "choices" in validated_data:
choices_data = validated_data.pop("choices")
question = Question.objects.create(**validated_data)
for choice_data in choices_data:
choice = Choice.objects.create(question=question, **choice_data)
return question
return Question.objects.create(**validated_data)
class PollSerializer(serializers.ModelSerializer):
author = serializers.HiddenField(default=serializers.CurrentUserDefault())
questions = QuestionSerializer(many=True, required=False)
class Meta:
model = Poll
fields = "__all__"
def create(self, validated_data):
if "questions" in validated_data:
questions_data = validated_data.pop("questions")
poll = Poll.objects.create(**validated_data)
for question_data in questions_data:
if "choices" in question_data:
choices_data = question_data.pop("choices")
question = Question.objects.create(poll=poll, **question_data)
for choice_data in choices_data:
choice = Choice.objects.create(question=question, **choice_data)
return poll
return Poll.objects.create(**validated_data)
class VoteSerializer(serializers.ModelSerializer):
class Meta:
model = Choice
fields = ["votes"]
def update(self, instance, validated_data):
instance.votes += 1
instance.save()
return instance
class ChoiceWithVotesSerializer(serializers.ModelSerializer):
class Meta:
model = Choice
fields = "__all__"
class QuestionWithVotesSerializer(serializers.ModelSerializer):
choices = ChoiceWithVotesSerializer(many=True, required=False)
class Meta:
model = Question
fields = "__all__"
class PollDetailsSerializer(serializers.ModelSerializer):
questions = QuestionWithVotesSerializer(many=True)
class Meta:
model = Poll
fields = "__all__"
还有显示投票的序列化程序,在具有自定义 IsPollAuthor 权限的视图中使用 - 仅供投票作者使用。当然,还有一个允许对经过身份验证的用户进行投票的序列化程序。 :)