没有/ <id>的请求中不允许使用方法PUT

时间:2019-06-02 17:01:09

标签: python django rest django-rest-framework

我有一个简单的ModelViewSet

class PersonViewSet(viewsets.ModelViewSet):
  queryset = Person.objects.all().order_by('id')
  serializer_class = PersonSerializer

还有urls.py

router = routers.DefaultRouter()
router.register(r'persons', views.PersonViewSet)

我需要申请PUT

  

/人

随身

{
  "id":10,
  "login":"alfredo",
  "avatar_url":"https://avatars.com/2222"
}

更新avatar_url。但是,当使用方法PUT用此URL'/ persons'进行调用时,我得到响应代码405

{
  "detail": "Method \"PUT\" not allowed."
}

(我知道这样做的更好方法是调用'/ persons / 10',但是该项目的要求是将PUT'/ persons'的ID放在主体请求中)

如何实现此端点?

2 个答案:

答案 0 :(得分:3)

尚未在ModelViewSet类上实现PUT方法,您可以在此处进行检查:http://www.cdrf.co/3.9/rest_framework.viewsets/ModelViewSet.html它是有关默认情况下实现了哪些方法的不错的文档。

要使您的PUT方法起作用,您应该添加以下代码:

d = {j:i for i, j in enumerate(List1)}
# {'Z': 0, 'Q': 1, 'X': 2, 'J': 3, 'K': 4, ...
''.join(sorted(List2, key = lambda x: d[x]))
# 'VRATE'

编辑:考虑到该URL为:def put(self, request, *args, **kwargs): return self.update(request, *args, **kwargs)

答案 1 :(得分:0)

您收到此错误,因为URL /person/不能与PUT请求一起使用。 PUT个请求对应于视图集update方法,而update方法要求URL中有一个ID,例如/person/10/,以便检索Person对象以进行更新。

实际解决此问题的方法是扩展DefaultRouter类以在列表端点上为PUT添加另一个操作,并自定义视图get_object方法以从中检索ID。有效载荷。

SimpleRouter类中,您将看到定义为的路由:

routes = [
    # List route.
    Route(
        url=r'^{prefix}{trailing_slash}$',
        mapping={
            'get': 'list',
            'post': 'create',
            'put': 'update'  # Add this entry to the mapping dictionary
        },
        name='{basename}-list',
        detail=False,
        initkwargs={'suffix': 'List'}
    ),
    # Dynamically generated list routes. Generated using
    # @action(detail=False) decorator on methods of the viewset.
    DynamicRoute(
        url=r'^{prefix}/{url_path}{trailing_slash}$',
        name='{basename}-{url_name}',
        detail=False,
        initkwargs={}
    ),
    # Detail route.
    Route(
        url=r'^{prefix}/{lookup}{trailing_slash}$',
        mapping={
            'get': 'retrieve',
            'put': 'update',
            'patch': 'partial_update',
            'delete': 'destroy'
        },
        name='{basename}-detail',
        detail=True,
        initkwargs={'suffix': 'Instance'}
    ),
    # Dynamically generated detail routes. Generated using
    # @action(detail=True) decorator on methods of the viewset.
    DynamicRoute(
        url=r'^{prefix}/{lookup}/{url_path}{trailing_slash}$',
        name='{basename}-{url_name}',
        detail=True,
        initkwargs={}
    ),
]

您需要将{'put': 'update'}添加到# List route.部分,然后自定义视图集的updateget_object方法,以便从视图集中检索ID。有效载荷。我将提供一个自定义get_object方法的示例来支持此用例:

def get_object(self):
    if self.action == "update" and self.kwargs.get(self.lookup_url_kwarg) is None:  # Check if this is an update method to the list view, the URL kwargs for the lookup will not be populated
        person_id = self.request.data.get("id")
        return Person.objects.get(pk=person_id)
    return super().get_object()