REST 上的奇怪行为:Update/patch View 不允许 get 方法和 returns 405 当通过请求调用时

Odd behaviour on REST: Update/patch View doesn't allow get method and returns 405 when called via requests

之前有人问过类似的问题,但我似乎无法通过答案解决我的问题。

我正在尝试部分更新一个对象,我在 REST 的通用 UpdateAPIView 中覆盖了 partial_update method,但是当我通过 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 方法添加到 class:

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

然后,更改为:

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

或尝试:

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

更新 2:

故障排除后:

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

可能的原因:您混淆了 url 中的 bldg 和建筑物,或者添加了另一个 url 参数,例如语言 deen