Метод PUT не разрешен в Resquest без / <id> - PullRequest
3 голосов
/ 02 июня 2019

У меня есть простой 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. Но при звонке с этим URL '/ персоналом' методом PUT я получаю код ответа 405

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

(я знаю, что лучший способ сделать это - позвонить «/ people / 10», но требование проекта - PUT «/ people» с идентификатором внутри запроса body)

Как я могу реализовать эту конечную точку?

Ответы [ 2 ]

3 голосов
/ 02 июня 2019

Метод PUT не реализован в классе ModelViewSet, вы можете проверить это здесь: http://www.cdrf.co/3.9/rest_framework.viewsets/ModelViewSet.html хорошая документация о том, какие методы реализованы по умолчанию.

Чтобы ваш метод PUT работал, вы должны добавить этот код:

def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

РЕДАКТИРОВАТЬ: учитывая, что URL-адрес: /persons/<id>

0 голосов
/ 04 июня 2019

Вы получаете эту ошибку, потому что URL /person/ не предназначен для использования с запросом PUT.PUT запросы соответствуют методу viewsets update, а для метода update требуется идентификатор в URL-адресе, например, /person/10/, чтобы получить объект Person для обновления.

Чтобы действительно решить эту проблему, можно расширить класс DefaultRouter, добавив еще одно действие для PUT в конечной точке списка, и настроить метод представлений get_object для получения идентификатора из полезной нагрузки.

В классе 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.и затем настройте методы update или get_object набора, чтобы он извлекал идентификатор из полезной нагрузки.Я приведу пример настроенного метода 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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...