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 参数,例如语言 de
、en
等
之前有人问过类似的问题,但我似乎无法通过答案解决我的问题。
我正在尝试部分更新一个对象,我在 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 参数,例如语言 de
、en
等