2015-08-17 170 views
4

我有一個API需要返回一個QuestionQueue及其關聯的Question對象作爲列表。我得到它很好地工作,它會返回我想要的數據:Django rest_framework 3.22多個更新創建對象而不是更新

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的更新方法,我已經在我的QuestionSerializer設置爲list_serializer_class

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 

的問題是,當我QuestionListSerializerupdate方法被調用,validated_data不包含問題的ID。他們都看起來像是新創造的。 request.data中的問題都有ID。他們在一路上被剝離出來。我不知道如何讓這個工作。

回答

0

問題是在DRF的ModelSerializerid字段爲read_only=True,因此它們在驗證週期中被丟棄。使更新工作需要更多的工作。我不得不爲DRF-bulk做類似的事情,而我最終得出的解決方案是創建一個序列化器mixin,將id放回。你可以看到源代碼here。我還在README有一些額外的信息。

萬一代碼被移動或類似的東西,這裏是串行混入的複製粘貼:

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

我試圖將此代碼複製到我的代碼庫,但我無法讓它工作。我左右絞盡腦汁,無濟於事。在'to_internal_value'的一些調用中,'context'不包含'view'。如果根是我列表的一個實例,它不包含'fields'。我準備放棄rest_framework,因爲要完成我所需要的任務非常困難。 –

+0

如果root是一個列表,它將不包含任何字段。 'root.child.field'將存在。 'ListSerializer'不包含任何字段。所有字段都回退到子序列化程序字段。 – miki725

0

我tomchristie談到了IRC。在我的序列化程序中添加一個明確的ID字段,並使其不read_only解決了問題。

相關問題