【问题标题】:Nested fields/objects creation with DRF使用 DRF 创建嵌套字段/对象
【发布时间】:2021-09-26 15:15:37
【问题描述】:

又是我对我正在处理的民意调查 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"}]}
    ]
}

【问题讨论】:

    标签: python django serialization django-rest-framework django-serializer


    【解决方案1】:

    你必须像这样使用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
    

    【讨论】:

    • 谢谢!我自定义了这些字段,并在 if 语句中嵌套了问题和选择的创建,并得到了我所需要的。有时最简单的解决方案就是正确的答案。 :)
    【解决方案2】:

    对于好奇的人,这是通过自定义 Reza 的答案创建的代码。

    序列化器.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 权限的视图中使用 - 仅对投票的作者可用。当然,还有一个允许对经过身份验证的用户投票的序列化程序。 :)

    【讨论】:

      猜你喜欢
      • 2020-10-03
      • 2018-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-02
      • 1970-01-01
      相关资源
      最近更新 更多