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

Vla*_*lad 26 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
        """
        .....
Run Code Online (Sandbox Code Playgroud)

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

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

我的网址是:

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

我的JS电话是:

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

在这种情况下,我希望我的描述能够更新,但是我得到了需要字段的错误(对于'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) 
Run Code Online (Sandbox Code Playgroud)

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

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

ram*_*win 19

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

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

文档
您无需编写partial_update或覆盖该update方法.只需使用该patch方法.

  • @NikhilBhardwaj 永远不要这样做。如果你想复用你的UpdateAPIView,你可以将你的UpdateAPIView中的代码封装成一个update_function,并在你的UpdateAPIView中以及其他你需要的地方调用该函数。 (2认同)

M.V*_*oid 9

请确保您有"补丁"http_method_names.或者你可以像这样写:

@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)]
Run Code Online (Sandbox Code Playgroud)

文件中所述:

默认情况下,序列化程序必须传递所有必填字段的值,否则会引发验证错误.您可以使用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)
Run Code Online (Sandbox Code Playgroud)

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

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

Serializer调用ModelSerializer的更新方法(参见来源):

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
Run Code Online (Sandbox Code Playgroud)

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


See*_*u S 7

patch方法适用于我viewset在 DRF 中使用。我正在改变你的代码:

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)
Run Code Online (Sandbox Code Playgroud)