Django rest_framework 3.22多个更新创建对象而不是更新

时间:2015-08-17 16:50:19

标签: python django rest django-rest-framework

我有一个API需要将QuestionQueue及其相关的Question对象作为列表返回。我得到了很好的工作,它返回我想要的数据:

class QuestionQueueSerializer(serializers.ModelSerializer):
    questions = QuestionSerializer(
        many=True,
        source='question_set',
        required=False,
    )

我无法获得有关此API的更新。我正在跟踪documentation多次写入。我有自己的名为ListSerializer的自定义QuestionListSerializer实例。这是我在QuestionQueueSerializer中使用它的方式:

def update(self, instance, validated_data):
    questions_data = validated_data.pop('question_set')
    super(QuestionQueueSerializer, self).update(instance, validated_data)
    question_list_serializer = QuestionSerializer(
        instance=instance.question_set.all(),
        data=questions_data,
        many=True
    )
    if question_list_serializer.is_valid():
        question_list_serializer.save(
            company_id=instance.company_id,
            question_queue_id=instance.id
        )
    return instance

这是QuestionListSerializer上的更新方法,我在list_serializer_class上设置为QuestionSerializer

def update(self, instance, validated_data):
    questions_by_id = {_question.id: _question for _question in instance}

    # Perform creations and updates.
    ret = []
    for question_data in validated_data:
        question = None
        if 'id' in question_data:
            question = questions_by_id.get(question_data['id'], None)
        if not question:
            ret.append(self.child.create(question_data))
        else:
            ret.append(self.child.update(question, question_data))

    question_ids_to_delete = set(questions_by_id.keys()) - {_q.id for _q in ret}
    Question.objects.filter(id__in=question_ids_to_delete).update(delete_ts=timezone.now())

    return ret

问题在于,当我的QuestionListSerializer update方法被调用时,validated_data不包含问题的ID。他们看起来都像是新创造的。 request.data中的问题都有ID。他们在途中被剥离了。我不知道如何让它发挥作用。

2 个答案:

答案 0 :(得分:0)

问题是,id字段在DRF的read_only=True中为ModelSerializer,因此它们会在验证周期中被删除。使更新工作需要更多的工作。我必须为DRF-bulk做类似的事情,我最终得到的解决方案是创建一个序列化器mixin,它会把id放回去。您可以看到源代码here。另外,我在README中有一些其他信息。

如果代码被移动或类似的东西,这里是序列化器mixin的复制粘贴:

class BulkSerializerMixin(object):
    def to_internal_value(self, data):
        ret = super(BulkSerializerMixin, self).to_internal_value(data)

        id_attr = getattr(self.Meta, 'update_lookup_field', 'id')
        request_method = getattr(getattr(self.context.get('view'), 'request'), 'method', '')

        # add update_lookup_field field back to validated data
        # since super by default strips out read-only fields
        # hence id will no longer be present in validated_data
        if all((isinstance(self.root, BulkListSerializer),
                id_attr,
                request_method in ('PUT', 'PATCH'))):
            id_field = self.fields[id_attr]
            id_value = id_field.get_value(data)

            ret[id_attr] = id_value

        return ret

答案 1 :(得分:0)

我在IRC上与tomchristie交谈过。在我的序列化程序中添加一个显式的id字段并使其不是read_only解决了这个问题。