Отключить метод в ViewSet, django-rest-framework


125

ViewSets иметь автоматические методы для перечисления, извлечения, создания, обновления, удаления, ...

Я хотел бы отключить некоторые из них, и решение, которое я придумал, вероятно, не очень хорошее, поскольку OPTIONSвсе еще заявляет, что они разрешены.

Есть идеи, как это сделать правильно?

class SampleViewSet(viewsets.ModelViewSet):
    queryset = api_models.Sample.objects.all()
    serializer_class = api_serializers.SampleSerializer

    def list(self, request):
        return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)
    def create(self, request):
        return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)

Ответы:


250

Определение ModelViewSet:

class ModelViewSet(mixins.CreateModelMixin, 
                   mixins.RetrieveModelMixin, 
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet)

Так ModelViewSetпочему бы просто не использовать то, что вам нужно, вместо того, чтобы расширяться ? Так например:

from rest_framework import viewsets, mixins

class SampleViewSet(mixins.RetrieveModelMixin,
                    mixins.UpdateModelMixin,
                    mixins.DestroyModelMixin,
                    viewsets.GenericViewSet):
    ...

При таком подходе маршрутизатор должен генерировать маршруты только для включенных методов.

Ссылка :

ModelViewSet


@SunnySydeUp Просто попробуйте это сейчас, и кажется, что маршрутизатор действительно генерирует маршрут для представления списка, но это 404, потому что ViewSet не знает, как обработать запрос. Вы этого ожидали?
— Steve Jalim

3
Используя только те миксины, которые вам нужны, вы можете отключить методы GET, POST, PUT, DELETE, но я не смог узнать, как отключить метод PATCH, особенно если вы используете маршрутизаторы.
— Muneeb Ahmad

3
@MuneebAhmad Метод PATCH включается из UpdateModelMixin. Если вы хотите использовать обновление, но не патч, я сейчас могу думать о двух способах. Вы можете либо переопределить разрешенные методы в представлении и удалить «патч», либо переопределить partial_updateметод и вызов http_method_not_allowed(request, *args, **kwargs). Я не тестировал это, поэтому я не уверен, работает ли это
— SunnySydeUp

1
@JulioMarins Я добавил ссылку. Я не уверен, что вы этого хотели.
— SunnySydeUp

1
Если кто-то хочет сделать viewset только для чтения, он может использовать class SampleViewSet(viewsets.ReadOnlyModelViewSet).
— Бикаш харел

133

Вы можете продолжать использовать viewsets.ModelViewSetи определять http_method_namesв своем ViewSet.

пример

class SampleViewSet(viewsets.ModelViewSet):
    queryset = api_models.Sample.objects.all()
    serializer_class = api_serializers.SampleSerializer
    http_method_names = ['get', 'post', 'head']

После того, как вы добавите http_method_names, вы больше не сможете делать putи patch.

Если хочешь, putно не хочешь patch, можешь оставитьhttp_method_names = ['get', 'post', 'head', 'put']

Внутренне представления DRF происходят от Django CBV. Django CBV имеет атрибут http_method_names. Таким образом, вы также можете использовать http_method_names с представлениями DRF.

[Shameless Plug]: Если этот ответ был полезен, вам понравится моя серия сообщений о DRF на https://www.agiliq.com/blog/2019/04/drf-polls/ .


16
Проблема с этим способом заключается в том, что нельзя отключить ни список, ни получение. Придется отключить оба или ни один из них
— Fuad

1
Это не сработало для меня, после включения get и head я все еще мог
— написать

Это работает для меня на django 1.9. Отличное решение. Есть ли риск, что пользователи могут выполнить запрос GET другим способом?
— Ycon

ФАНТАСТИЧЕСКОЕ решение. Работает python3и Django 1.10отлично.
— Urda

2
Я предпочитаю этот подход, потому что я не мог изменить наследование миксинов, чтобы включить PATCH, но не PUT, потому что они оба являются реализацией mixins.UpdateModelMixin
— ThatsAMorais

5

Хотя для этой публикации прошло некоторое время, я внезапно обнаружил, что на самом деле это способ отключить эту функцию, вы можете редактировать его напрямую в views.py.

Источник: https://www.django-rest-framework.org/api-guide/viewsets/#viewset-actions

from rest_framework import viewsets, status
from rest_framework.response import Response

class NameWhateverYouWantViewSet(viewsets.ModelViewSet):

    def create(self, request):
        response = {'message': 'Create function is not offered in this path.'}
        return Response(response, status=status.HTTP_403_FORBIDDEN)

    def update(self, request, pk=None):
        response = {'message': 'Update function is not offered in this path.'}
        return Response(response, status=status.HTTP_403_FORBIDDEN)

    def partial_update(self, request, pk=None):
        response = {'message': 'Update function is not offered in this path.'}
        return Response(response, status=status.HTTP_403_FORBIDDEN)

    def destroy(self, request, pk=None):
        response = {'message': 'Delete function is not offered in this path.'}
        return Response(response, status=status.HTTP_403_FORBIDDEN)

Это должен быть предпочтительный способ.
— digitake

Я думаю, что HTTP_400_BAD_REQUEST здесь будет более подходящим, если он не связан с auth.
— Сантьяго Магариньос,

4

Если вы пытаетесь отключить метод PUT в представлении DRF, вы можете создать собственный маршрутизатор:

from rest_framework.routers import DefaultRouter

class NoPutRouter(DefaultRouter):
    """
    Router class that disables the PUT method.
    """
    def get_method_map(self, viewset, method_map):

        bound_methods = super().get_method_map(viewset, method_map)

        if 'put' in bound_methods.keys():
            del bound_methods['put']

        return bound_methods

Отключив метод на маршрутизаторе, ваша документация по схеме API будет правильной.


Как частичный патч не корректно реализован в ФПИ было бы целесообразно , чтобы удалить его глобально так , как описано здесь
— Оден

1

Как отключить метод "DELETE" для ViewSet в DRF

class YourViewSet(viewsets.ModelViewSet):
    def _allowed_methods(self):
        return [m for m in super(YourViewSet, self)._allowed_methods() if m not in ['DELETE']]

PS Это более надежно, чем явное указание всех необходимых методов, поэтому меньше шансов забыть некоторые важные методы OPTIONS, HEAD и т. Д.

PPS по умолчанию DRF имеет http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']


Вы не можете позвонить superна уровне класса, нет self.
— validname

0

В Django Rest Framework 3.xx вы можете просто включить каждый метод, для которого хотите включить ModelViewSet, передав словарь в as_viewметод. В этом словаре ключ должен содержать тип запроса (GET, POST, DELETE и т. Д.), А значение должно содержать соответствующее имя метода (список, получение, обновление и т. Д.). Например, предположим, что вы хотите Sampleсоздать или прочитать модель, но не хотите ее изменять. Так что это означает , что вы хотите list, retrieveи createметод будет включить (и вы хотите , чтобы другие были отключены.)

Все, что вам нужно сделать, это добавить такие пути urlpatterns:

path('sample/', SampleViewSet.as_view({
    'get': 'list',
    'post': 'create'
})),
path('sample/<pk>/', SampleViewSet.as_view({  # for get sample by id.
    'get': 'retrieve'
}))

Как вы можете видеть, в приведенных выше настройках маршрутизации нет запроса deleteи put, поэтому, например, если вы отправляете putзапрос на URL-адрес, он отвечает вам 405 Method Not Allowed:

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.