REST上的异常行为:更新/补丁视图不允许使用get方法,并通过请求调用时返回405

问题描述

之前也曾提出过类似的问题,但是我似乎无法用答案来解决问题。

我正在尝试部分更新对象,并且重写了REST的通用partial_update method中的UpdateAPIView,但是当我通过requests调用此视图时,我得到了405:get method not allowed响应

非常奇怪的是我的代码运行了大约2周,现在突然间我收到此错误。我把头撞在墙上,似乎无法弄清楚。

我认为我正在这样做:

class BuildingUpdateAPI(UpdateAPIView):
    serializer_class = BuildingSerializer

    def partial_update(self,request,*args,**kwargs):
        """Patches building specified in URL with data in request."""

        network = Network.objects.get(name=self.kwargs["name_network"])
        building = network.buildings.get(name=self.kwargs["name_building"])

        serializer = BuildingSerializer(building,data=request.data,partial=True)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(status=200,data=serializer.data)
        msg = (
            "Error message"
        )
        return JsonResponse(status=400,data=msg,safe=False)

我的序列化器很简单,它仅定义字段(但如果有帮助,我可以提供)。

在其他答案中,据说REST正在寻找get-method并且找不到它。但是我不是通过get而是通过patch来称呼它:

ep = "http://localhost:8000/path/to/update/"
data = {
   "update_field": "123"
}
r = requests.request("patch",url=ep,data=data,headers=get_headers())

其他答案说我输入了错误的URL,但是我很确定这是正确的URL。再说一次,这是可行的,而现在却没有。还是我不能在更新方法调用Network.objects.get?但是那我怎么办...

并使这个事情变得更加荒谬:我可以使用REST接口进行更新。但是通过请求发送补丁请求会给我这个错误(但是我需要通过请求来做到这一点)

我真的没有选择,非常感谢您的帮助。提前致谢。如果我可以提供更多代码或信息,请输入lmk。

谢谢。

更新:同样通过Postman尝试此操作也会产生相同的错误,因此我认为请求不是问题。

urls.py:

urlpatterns = [
    path(
        "api/v1/networks/<int:pk>/",NetworkDetailAPIById.as_view(),name="networks-detail-api-id",),path(
        "api/v1/networks/<str:name>/",NetworkDetailAPIByName.as_view(),name="networks-detail-api-name",path(
        "api/v1/networks/update/<int:pk>/",NetworkUpdateAPI.as_view(),name="networks-update-api",path(
        "api/v1/networks/buildings/new/",NetworkBuildingCreateAPI.as_view(),name="networks-buildings-create-api",path(
        "api/v1/networks/project/<str:project_name>",NetworkProjectListAPI.as_view(),name="networks-project-list-api",path(
        "api/v1/buildings/<int:id>/",BuildingRetrieveAPI.as_view(),name="buildings-detail-api",path(
        "api/v1/buildings/delete/<int:id>",BuildingDeleteAPI.as_view(),name="buildings-delete-api",path(
        "api/v1/buildings/update/<str:name_network>/<str:name_building>",BuildingUpdateAPI.as_view(),name="buildings-update-api",path(
        "api/v1/network/buildings/<str:name_network>/",BuildingByNetworkListAPI.as_view(),name="network-buildings-list-api",path(
        "api/v1/time-series/",TimeSeriesAPI.as_view(),name="time-series-list-create-api",path(
        "api/v1/time-series/network/building/type-data/<str:name_network>/<str:name_building>/<str:type_data>/",TimeSeriesBuildingInNetworkAPI.as_view(),name="time-series-building-data-type-detail-api",path(
        "api/v1/time-series/project/type-data/step/<str:project>/"
        "<str:type_data>/<str:time_step>/",TimeStampBuildingsAPI.as_view(),name="timestamp-detail-api",path("api/v1/bldg/<str:name_network>/<str:name_building>/",SampleCreate.as_view(),name="sample")
]

添加get时出错:


500
<!DOCTYPE html>
<html lang="en">
<head>
  <Meta http-equiv="content-type" content="text/html; charset=utf-8">
  <Meta name="robots" content="NONE,NOARCHIVE">
  <title>AssertionError
          at /de/api/v1/bldg/TestDevNetworkBuilding4/Demand_1/</title>
  <style type="text/css">
    html * { padding:0; margin:0; }


..... plus a bunch of html 

解决方法

您的路径缺少端口组件:

ep = "http:localhost:/path/to/update/"

应该是这样的:

ep = "http:localhost:5000/path/to/update/"

更新:

尝试向该类添加patch方法:

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

然后,更改为:

r = requests.request("PATCH",url=ep,data=data,headers=get_headers())

或尝试:

r = requests.patch(url=ep,headers=get_headers())

更新2:

故障排除后:

这是来自/de/api/v1/bldg/TestDevNetworkBuilding4/Demand_1的声明错误,与您的SampleCreate.as_view() URL模式匹配。网址匹配path("api/v1/bldg/<str:name_network>/<str:name_building>/"

可能的原因:您在网址中混淆了建筑物和建筑物,或者添加了其他网址参数,例如语言deen等。