【问题标题】:Does rest_framework coreapi not support PUT / PATCH?rest_framework coreapi 不支持 PUT / PATCH 吗?
【发布时间】:2017-11-07 19:59:18
【问题描述】:

我想使用Python Client Library,但是让 PUT/PATCH 工作的痛苦无穷无尽。每当我尝试使用 update / partial_update 时,都不会从字典中插入 URL 参数,并且服务器会返回 404。

[06-Jun-2017 12:30:05] WARNING [django.server:124] "PUT /api/accounts/networks/%7Bcid%7D/ HTTP/1.1" 404 23

这清楚地表明 {cid} 参数从未被实际值替换。这让我想到了我的问题的 TL/DR 版本,CoreAPI 不支持 PUT / PATCH 吗?

PUT / PATCH 选项已根据以下信息正确设置:

GET /api/accounts/networks/2892c424-3a86-16bb-8b60-12a79900e90c/
HTTP 200 OK
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "url": "http://localhost:8000/api/accounts/networks/2892c424-3a86-16bb-8b60-12a79900e8fb/",
    "created": "2016-04-16T19:35:02.169898Z",
    "modified": "2017-05-30T17:25:29.768740Z",
    "cid": "2892c424-3a86-16bb-8b60-12a79900e8fb",
    "name": "10.0.0.0/8",
    "comments": "Local Area Network - 10.x",
    "builtin": true
}

现在我花了一个上午的大部分时间来尝试完成这项工作,我意识到有 no documentation example 显示更新/部分更新。

所以我想我会尝试改用coreapi-cli,但我遇到了同样的问题。

coreapi action networks partial_update --param cid='2892c424-3a86-16bb-8b60-12a79900e8fb' --param comments='this is WAAAY too hard'
<Error: 404 Not Found>
    detail: "Not found."

Django 的日志显示 URL 参数从未被提供的“cid”参数替换:

[06-Jun-2017 13:07:01] WARNING [django.server:124] "PUT /api/accounts/networks/%7Bcid%7D/ HTTP/1.1" 404 23

我可以使用覆盖参数来强制 URL,现在它会按预期更新。

client.action(['networks', 'partial_update'],
          params={'comments': 'this is WAAAY too hard', 'cid': '2892c424-3a86-16bb-8b60-12a79900e8fb'},
          overrides={'url': 'http://localhost:8000/api/accounts/networks/2892c424-3a86-16bb-8b60-12a79900e8fb/'},
          )

但这感觉很糟糕,应该完全没有必要。所以...

  1. 这是一个错误吗?
  2. 我的函数签名有误吗?
  3. CoreAPI 不支持 PUT / PATCH 方法吗?

编辑

这是视图集

class LCModelViewSet(mixins.CreateModelMixin,
                     mixins.RetrieveModelMixin,
                     mixins.UpdateModelMixin,
                     mixins.DestroyModelMixin,
                     mixins.ListModelMixin,
                     GenericViewSet):
    """
    Base ModelViewSet
    """
    lookup_field = 'cid'



class NetworksViewSet(LCModelViewSet):
    queryset = Networks.objects.all()
    serializer_class = NetworksSerializer
    filter_class = NetworksFilter

和路由器

router = DefaultRouter()
router.register(r'accounts/networks', av.NetworksViewSet, base_name='api-networks')

以及router.routes的输出

[Route(url='^{prefix}{trailing_slash}$', mapping={'get': 'list', 'post': 'create'}, name='{basename}-list', initkwargs={'suffix': 'List'}),
 DynamicListRoute(url='^{prefix}/{methodname}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={}),
 Route(url='^{prefix}/{lookup}{trailing_slash}$', mapping={'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'}, name='{basename}-detail', initkwargs={'suffix': 'Instance'}),
 DynamicDetailRoute(url='^{prefix}/{lookup}/{methodname}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={})]

编辑#2

根据hurturk 的建议,我将所有内容都减少为默认值 - views.ModelViewsetserializers.ModelSerializer,并将 lookup_field 放在 NetworksViewSet 上。还是一样的问题。

然后我删除了自定义查找字段,并尝试使用默认的 id 字段(cid 不是 PK),然后 VOILA、PUT/PATCH 工作 - URL 生成正确!所以,我想知道是否出于某种原因它是一个与 UUID 相关的问题。

由于name 是一个唯一字段,我设置了lookup_field = name。与 UUID 相同的行为。 GET/POST 方法有效。 PUT/PATCH 不要"PATCH /api/accounts/networks/%7Bname%7D/ HTTP/1.1" 404 23

看来,当lookup_field 是PK 时,PUT/PATCH url 会正确生成。当lookup_field 是其他字段时,永远不会插入 URL lookup_field 占位符。

我不知道该怎么办。 CID 是必备要求...

【问题讨论】:

  • 您的视图看起来如何? CoreAPI 首先获取 DRF 提供的架构。
  • 看起来像 CoreAPI 的一个错误,因为它已经是参数安全的。还有两个问题,你在哪里定义你的lookup_field?以防万一,您可以注释掉过滤器并重试吗?您还可以从cid 中删除引号,这也可以。
  • 我简化了这张票中的视图集,忘记了编辑从票号中删除了 lookup_field 声明。现在编辑了问题,并显示了视图集类层次结构。我没有关注您关于“从cid 中删除引号。应该在哪里完成?
  • 哦,我的意思是coreapi-cli,但应该没什么区别。我仍然认为这是一个错误,您的代码和调用对我来说看起来很完美。您可以删除继承的类,将NetworksViewSet 中的lookup_field 移动并让它从viewsets.ModelViewSet 扩展,然后再报告此问题(以证明最小示例不起作用)。
  • 我已经用python 3.4.3coreapi 2.3.1coreapi-cli 1.0.6django 1.11djangorestframework 3.6.2 测试了你的模型,效果很好。

标签: python django django-rest-framework core-api


【解决方案1】:

好吧,我找到了问题所在。 :-) cid 必须设置为只读,然后正确形成 PUT/PATCH 的 URL。

为什么lookup_field 必须是只读的?如果让 lookup_field 可写是不正确且不可行的,则错误消息将非常有用,而不是当前行为。

编辑

谢谢你,@hurkurk!我没有注意到你的PR!这确实解决了我的问题,至少在不需要编辑 cid 时。将路径参数与请求数据分开指定真的很棒,这样lookup_field 的值就可以在 PUT/PATCH 上更改。但这是另一个讨论。

【讨论】:

  • 听起来不错! Readonly 可能消除了路径与数据之间的混淆,但我认为错误仍然存​​在。我会等着看项目维护者何时给它一个方向,因为这也是 restful 设计中的讨论是否 PUT/PATCH 是否应该重命名资源,而在 DRF 中允许这样做没有问题。
【解决方案2】:

这肯定是 CoreAPI http 传输的一个错误,因为它假设架构中的所有字段名称都是不同的。我提供了一个PR 来修复它,但这可能需要项目所有者进一步的设计考虑。

正如您还提到的,将查找字段设为只读是该问题的另一种解决方案,因为这将导致它在字段分析中仅出现一次。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-07
    • 1970-01-01
    • 2020-04-11
    • 2021-09-09
    • 2019-11-01
    • 2022-06-15
    • 2020-08-27
    • 1970-01-01
    相关资源
    最近更新 更多