【问题标题】:DRF Serializer update list of nested objectsDRF Serializer 更新嵌套对象列表
【发布时间】:2019-11-23 01:26:02
【问题描述】:

我使用 Django-rest-framework 编写投票应用程序项目。它有两种模型:问题和嵌套答案。我想根据要求更新问题序列化程序的答案,例如:

{
    "question":"question",
    "answers": [{"answer":"first updated answer"}, {"answer":"second update answer"}]
}

我怎样才能正确地做到这一点?我尝试这样做,但是我删除了每个请求中的答案并创建了新答案,因为每次都会更改他们的 ID。

serializer.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

models.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)

【问题讨论】:

    标签: django python-3.x django-rest-framework django-serializer


    【解决方案1】:

    经过数小时的文档浏览后才发现这一点:

    serializer.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
    

    【讨论】:

      【解决方案2】:

      试试这个

      def update(self, instance, validated_data):
      
          if 'answers' in validated_data:
              answer_ids_new = []
              answer_ids_pre = instance.answers.all().values_list('id', flat=True)
              for answer in validated_data.pop('answers'):
                  ans, _created = Answer.objects.get_or_create(**answer)
                  ans.question = instance
                  ans.save()
                  answer_ids_new.append(ans.id)
      
              delete_ids = set(answer_ids_pre) - set(answer_ids_new)
              Answer.objects.filter(id__in=delete_ids).delete()
          for item, value in validated_data.items():
              setattr(instance, item, value)
          instance.save()
          return instance
      


      注意:我没有尝试解决方案

      【讨论】:

      • id还在变化。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-04
      • 2018-12-23
      • 2020-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多