Django rest_framework 3.22 multiple updates creating objects instead of updating

I have an API that should return a QuestionQueue and related Question objects in a list. I got it so that it works well, and it returns the data as I want it:

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

I'm having trouble getting updates to work on this API. I follow the documentation for several entries. I have my own custom ListSerializer instance called QuestionListSerializer . This is how I use it in 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 

Here's the update method on QuestionListSerializer , which I set as list_serializer_class on my 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 

The problem is that when calling the QuestionListSerializer method update validated_data does not contain question identifiers. They all look as if they were recently created. The questions in request.data all have identifiers. They get out somewhere along the way. I do not know how to make this work.

+4
source share
2 answers

The problem is that the id fields are read_only=True in the DRF ModelSerializer , so they are discarded in the check loop. Performing an upgrade to work requires more work. I had to do something similar for DRF-bulk , and the solution I ultimately provided was to create a serializer mix that would return an identifier. Here you can see the source code here . I also have additional information in README .

In case the code moves or something like that, here copy the mixizer serializer palette:

 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 
0
source

I talked to tomchristie on the IRC. Adding an explicit id field to my serializer and its inability to read_only solve the problem.

0
source

All Articles