HTTP PUT не работает должным образом в среде django rest

Я использую следующий код в фреймворке django rest для достижения функциональности ввода и исправления. PATCH (partial_update) работает нормально, однако предоставление меньшего количества полей для PUT не заменит весь ресурс, как это должен делать запрос PUT. Например, если данные выглядят следующим образом:

{
"id": 6,
"name": "crticial MVP",
"description": "getting things done",
"end": "2012-02-18"   
}

И если я попытаюсь выполнить PUT со следующими данными (на http://localhost:800/api/sprints/ 6/):

{
    "name": "critical MVP2", 
    "end": "2012-02-18"
}

Этот вызов должен установить для описания значение none. Но описание сохраняет свое значение, как если бы я делал ПАТЧ. Как я могу обеспечить замену ресурсов в функции обновления?

PS: я установил partial=False при инициализации сериализатора для обновления.

просмотров.py:

class SprintViewSet(viewsets.ModelViewSet):
    queryset = Sprint.objects.order_by('end')
    serializer_class = SprintSerializer 
    def update(self, request, *args, **kwargs):
        sprint=self.get_object()                        
        serializer = SprintSerializer(sprint, data=request.data, partial=False,
 context={'request': request, 'view':self, 'format':None})
        serializer.is_valid(raise_exception=True)       
        serializer.save()
        return Response(serializer.data)
    def partial_update(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = SprintSerializer(instance, data=request.data, partial=True,
 context={'request': request, 'view':self, 'format':None})
        serializer.is_valid(raise_exception=True)
        new_instance = serializer.save()
        return Response(serializer.data)

сериализаторы.py:

class SprintSerializer(serializers.ModelSerializer):
    links = serializers.SerializerMethodField()
    class Meta:     
        model = Sprint              
        fields = ('id', 'name', 'description', 'end', 'links')
    def get_links(self, obj):
        request = self.context['request'] 
        return {
                'self': reverse('sprint-detail',
                kwargs={'pk': obj.pk},request=request),
                }

модели.py

class Sprint(models.Model): 
    name = models.CharField(max_length=100, blank=True, default='')
    description = models.TextField(blank=True, default='')
    end = models.DateField(unique=True)
    def __str__(self):
        return self.name or _('Sprint ending %s') % self.end

person Mehdi Karamnejad    schedule 31.03.2015    source источник


Ответы (1)


PUT ожидает, что передается полный объект данных, поэтому любые атрибуты модели заменяются переданными данными. Но для этого требуется, чтобы был передан полный объект данных, поэтому, если вы не передаете поле то он будет игнорироваться в зависимости от того, как данные отправляются.

Если вы отправляете данные, используя данные формы (AJAX без JSON или HTML <form>), то поле будет полностью проигнорировано. В основном это связано с тем, что некоторые браузеры не отправляют определенные поля (например, флажки), если значение не установлено, поэтому DRF вручную переопределяет его в таких ситуациях.

Если вы используете JSON и поле не является обязательным (что похоже на ваш случай), DRF переопределит значение только в том случае, если ключ передается в запрос. Это связано с тем, что PUT предполагается, что он содержит полный объект данных, и DRF делает несколько предположений, основанных на этом.

person Kevin Brown    schedule 31.03.2015