rest_framework coreapi不支持PUT / PATCH吗?

时间:2017-06-06 17:22:37

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

我想要使用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} param从未被实际值取代。这让我想到了我的问题的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”替换。 param提供:

[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方法吗?
  4. 修改

    这里是视图集

    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

    根据Injurk的建议,我将所有内容缩减为默认值 - 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是其他字段,则永远不会插入网址lookup_field占位符。

    我不知道该怎么做。 CID是必须要求的......

2 个答案:

答案 0 :(得分:1)

好吧,我发现了这个问题。 :-) cid必须设置为readonly,然后正确形成PUT / PATCH的URL。

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

修改

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

答案 1 :(得分:0)

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

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