【问题标题】:Django Rest Framework using nested serializer for posting data two modelsDjango Rest Framework 使用嵌套序列化器发布数据两个模型
【发布时间】:2019-08-02 07:11:06
【问题描述】:

我一直在使用 Django rest 框架来创建 API。在这个 API 中有两个模型 Question 和 Option。 Question 在 Option 中是 Foreign Key。我一直在尝试以一个表单获取所有字段并将数据添加到相应的模型中。
对于一个问题,选项可以与表单提供的一样多。我尝试为已经存在的问题创建选项(即,将在数据库中添加第一个问题,然后选择问题并添加该问题的选项),我认为这不是实用的方法,所以我有一个想法,即在创建问题时需要将选项添加到数据库中。

models.py

class Question(models.Model):
    body = RichTextField()


class Option(models.Model):
    question = models.ForeignKey(Question, on_delete=CASCADE)
    number = models.IntegerField()
    option = RichTextField()
    is_correct = models.SmallIntegerField()

serializers.py

class QuestionSerializers(serializers.ModelSerializer):
    class Meta:
        model = Questions
        fields = ('id', 'body', 'explanation')


class QuestionReadSerializer(serializers.ModelSerializer):
    question = QuestionSerializers()

    class Meta:
        model = Options
        fields = ('question', 'number', 'option', 'is_correct')


class QuestionWriteSerializers(serializers.ModelSerializer):
    question = QuestionSerializers()

    class Meta:
        model = Options
        fields = ('question', 'number', 'option', 'is_correct')

    @transaction.atomic
    def create(self, validated_data):
        question_data = validated_data.pop('question')
        question = Questions.objects.update_or_create(**question_data)
        option = Options.objects.update_or_create(question=question[0], **validated_data)

        return option[0]

views.py

class QuestionViewset(viewsets.ModelViewSet):
    queryset = Options.objects.all()
    def get_serializer_class(self):
        if self.request.method == 'POST':
            return QuestionWriteSerializers
        return QuestionReadSerializers

我正在使用选项模型为特定问题创建新选项,如果问题是新问题,则将创建新问题。但这不是最好的方法。任何帮助都会得到帮助。

【问题讨论】:

    标签: django django-models django-rest-framework django-views


    【解决方案1】:

    如果需要,您可以覆盖问题视图集的创建以处理有效负载中提供的选项。此外,IMO 你真的不需要两组序列化器来解决问题。带有建议的最终代码应如下所示:


    models.py

    class Question(models.Model):
        body = RichTextField()
    
    
    class Option(models.Model):
        question = models.ForeignKey(Question, related_name='options', on_delete=CASCADE)
        number = models.IntegerField()
        option = RichTextField()
        is_correct = models.SmallIntegerField()
    

    serializers.py

    class QuestionSerializer(serializers.ModelSerializer):
        class Meta:
            model = Questions
            fields = ('id', 'body', 'explanation')
    
    
    class OptionSerializer(serializers.ModelSerializer):
        question = QuestionSerializer()
    
        class Meta:
            model = Options
            fields = ('question', 'number', 'option', 'is_correct')
    

    views.py

    class QuestionViewset(viewsets.ModelViewSet):
        serializer_class = QuestionSerializer
    
        def create(self, request, *args, **kwargs):
            options = request.data.pop("options", [])
            _question = super(QuestionViewset, self).create(request, *args, **kwargs)
            for option in options:
                option["question"] = _question.id
                serializer = OptionSerializer(data=option)
    
                # I would recommend to delete the added question + options 
                # in case is_valid returns False, depends on your req.
                assert serializer.is_valid()
                serializer.save()
    
            return _question
    

    【讨论】:

    • options = request.data.pop("options", [])从哪里可以得到字段名options中的数据,请看一下
    • 这将包含在您可以发送到与question 资源相关的 POST API 的数据中
    • 好的,我明白你的意思了,这里的问题是在_question 中:option["question"] = _question.id 错误是:AttributeError: 'Response' object has no attribute 'id'
    • 您应该能够使用_question.data["id"],因为_question 是来自DRF 的响应类型
    • 你能看一下这个问题的更解释版本吗question asked in stackoverflow
    猜你喜欢
    • 2019-06-02
    • 2018-06-04
    • 1970-01-01
    • 2017-01-16
    • 1970-01-01
    • 2018-06-23
    • 1970-01-01
    • 1970-01-01
    • 2015-03-20
    相关资源
    最近更新 更多