Отключить метод в 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)
DB0
источник

Ответы:

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
источник
@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']

pymen
источник
Вы не можете позвонить 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."
}
Hamidreza
источник