如何使用DJANGO REST框架发出PATCH请求

时间:2014-01-15 20:57:43

标签: django django-rest-framework

我对Django REST框架不是很熟悉,并且已经尝试了很多东西但是无法使我的PATCH请求工作。

我有一个模型序列化器。这与我用来添加新条目的条目相同,理想情况下我想在更新条目时重复使用。

class TimeSerializer(serializers.ModelSerializer):
    class Meta:
        model = TimeEntry
        fields = ('id', 'project', 'amount', 'description', 'date')

    def __init__(self, user, *args, **kwargs):
        # Don't pass the 'fields' arg up to the superclass
        super(TimeSerializer, self).__init__(*args, **kwargs)
        self.user = user

    def validate_project(self, attrs, source):
        """
        Check that the project is correct
        """
        .....

    def validate_amount(self, attrs, source):
        """
        Check the amount in valid
        """
        .....

我尝试使用基于类的视图:

class UserViewSet(generics.UpdateAPIView):
    """
    API endpoint that allows timeentries to be edited.
    """
    queryset = TimeEntry.objects.all()
    serializer_class = TimeSerializer

我的网址是:

url(r'^api/edit/(?P<pk>\d+)/$', UserViewSet.as_view(), name='timeentry_api_edit'),

我的JS电话是:

var putData = { 'id': '51', 'description': "new desc" }
$.ajax({
    url: '/en/hours/api/edit/' + id + '/',
    type: "PATCH",
    data: putData,
    success: function(data, textStatus, jqXHR) {
        // ....
    }
}

在这种情况下,我希望我的描述能够更新,但是我得到了需要字段的错误(对于'project'和所有其他字段)。验证失败。如果添加到AJAX调用所有字段,它仍然无法检索“项目”。

我也尝试过自己的观点:

@api_view(['PATCH'])
@permission_classes([permissions.IsAuthenticated])
def edit_time(request):

if request.method == 'PATCH':
    serializer = TimeSerializer(request.user, data=request.DATA, partial=True)
    if serializer.is_valid():
        time_entry = serializer.save()
    return Response(status=status.HTTP_201_CREATED) 
return Response(status=status.HTTP_400_BAD_REQUEST) 

由于相同的原因(对于字段的验证失败),这对于部分更新不起作用,即使我已经发送了所有字段,它也不起作用。它创建一个新条目,而不是编辑现有条目。

我想重复使用相同的序列化程序和验证,但我愿意接受任何其他建议。 此外,如果有人有一段工作代码(ajax代码 - &gt; api view-&gt;序列化器)会很棒。

6 个答案:

答案 0 :(得分:12)

class DetailView(APIView):
    def get_object(self, pk):
        return TestModel.objects.get(pk=pk)

    def patch(self, request, pk):
        testmodel = self.get_object(pk)
        serializer = TestModelSerializer(testmodel, data=request.data, partial=True) # set partial=True to update a data partially
        if serializer.is_valid():
            serializer.save()
            return JsonReponse(code=201, data=serializer.data)
        return JsonResponse(code=400, data="wrong parameters")

Documentation
您无需编写partial_update或覆盖update方法。只需使用patch方法。

答案 1 :(得分:7)

确保 http_method_names 中有“PATCH”。或者你可以这样写:

@property
def allowed_methods(self):
    """
    Return the list of allowed HTTP methods, uppercased.
    """
    self.http_method_names.append("patch")
    return [method.upper() for method in self.http_method_names
            if hasattr(self, method)]

documentation中所述:

  

默认情况下,序列化程序必须为所有必填字段传递值,否则会引发验证错误。您可以使用partial参数以允许部分更新。

在视图中覆盖update方法:

def update(self, request, *args, **kwargs):
    instance = self.get_object()
    serializer = TimeSerializer(instance, data=request.data, partial=True)
    serializer.is_valid(raise_exception=True)
    serializer.save(customer_id=customer, **serializer.validated_data)
    return Response(serializer.validated_data)

或者只是在视图中覆盖方法partial_update

def partial_update(self, request, *args, **kwargs):
    kwargs['partial'] = True
    return self.update(request, *args, **kwargs)

序列化程序调用 ModelSerializer 更新方法(请参阅sources):

def update(self, instance, validated_data):
    raise_errors_on_nested_writes('update', self, validated_data)

    # Simply set each attribute on the instance, and then save it.
    # Note that unlike `.create()` we don't need to treat many-to-many
    # relationships as being a special case. During updates we already
    # have an instance pk for the relationships to be associated with.
    for attr, value in validated_data.items():
        setattr(instance, attr, value)
    instance.save()

    return instance

更新将 validated_data 值推送到给定实例。请注意,更新不应假定所有字段都可用。这有助于处理部分更新( PATCH 请求)。

答案 2 :(得分:4)

我在DRF中使用patchviewset方法工作。我改变你的代码:

class UserViewSet(viewsets.ModelViewSet):
    queryset = TimeEntry.objects.all()
    serializer_class = TimeSerializer

    def perform_update(self, serializer):
        user_instance = serializer.instance
        request = self.request
        serializer.save(**modified_attrs)
        return Response(status=status.HTTP_200_OK)

答案 3 :(得分:0)

改为使用UpdateModelMixin并覆盖class UserViewSet(viewsets.ModelViewSet): queryset = TimeEntry.objects.all() serializer_class = TimeSerializer def perform_update(self, serializer): serializer.save() # you may also do additional things here # e.g.: signal other components about this update

中的UpdateModelMixin方法
update

就是这样。不要在此方法中返回任何内容。 _prefetched_objects_cache已经实施了.background{ background-image: url('../assets/bg/chatbg1.jpg'); background-size: cover; background-attachment: fixed; /*-- here should be fixed --*/ } .messageLeft{ float: left; display: inline; padding: 4px 5px; background-color: transparent;/*-- make background transparent--*/ margin: 5px; color: black; border-radius: 3px; word-break: break-all; //width: 250px; } .messageRight{ float: right; display: inline; padding: 4px 5px; background-color: transparent; /*-- make background transparent--*/ margin: 5px; color: black; border-radius: 3px; word-break: break-all; //width: 250px; 方法,可以将更新的数据作为回复返回给您,并清除Story <-- 1 ----- N --> StoryLocation 。请参阅outer product

答案 4 :(得分:0)

我也遇到了这个问题,我解决了它,重新定义了get_serializer_method并添加了自定义逻辑来处理部分更新。 Python 3

 class ViewSet(viewsets.ModelViewSet):
     def get_serializer_class(self):
         if self.action == "partial_update":
             return PartialUpdateSerializer

注意:您可能必须重写序列化程序上的partial_update函数。像这样:

class PartialUpdateSerializer(serializers.Serializer):
    def partial_update(self, instance, validated_data):
       *custom logic*
       return super().update(instance, validated_data)

答案 5 :(得分:0)

另一种可能性是通过URL发出请求。例如,我有一个这样的模型

      class Author(models.Model):
        FirstName = models.CharField(max_length=70)
        MiddleName = models.CharField(max_length=70)
        LastName = models.CharField(max_length=70)
        Gender = models.CharField(max_length=1, choices = GENDERS)
        user = models.ForeignKey(User, default = 1, on_delete = models.CASCADE, related_name='author_user')
        IsActive = models.BooleanField(default=True)
        class Meta:
          ordering = ['LastName']

还有这样的视图

      class Author(viewsets.ModelViewSet):
        queryset = Author.objects.all()
        serializer_class = AuthorSerializer

因此可以输入http://127.0.0.1:8000/author/来吸引或发表作者。如果我要发出PATCH请求,则可以从您的客户端指向http://127.0.0.1:8000/author/ID_AUTHOR。例如在angular2中,您可以拥有类似的内容

       patchRequest(item: any): Observable<Author> {
        return this.http.patch('http://127.0.0.1:8000/author/1', item);
       }

假设您已经配置了CORS,并且前后具有相同的模型。 希望它会有用。