禁用 ViewSet,django-rest-Framework 中的方法

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)
74860 次浏览

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

您可以继续使用 viewsets.ModelViewSet并在 ViewSet 上定义 http_method_names

例子

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

一旦你添加 http_method_names,你将不能再做 putpatch

如果你想要 put但不想要 patch,你可以保留 http_method_names = ['get', 'post', 'head', 'put']

在内部,DRF 视图扩展自 Django CBV。Django CBV 有一个名为 http _ method _ Names 的属性。因此,您也可以对 DRF 视图使用 http _ method _ name。

[无耻的插头] : 如果这个答案是有帮助的,你会喜欢我在 https://www.agiliq.com/blog/2019/04/drf-polls/的 DRF 系列文章。

如果您试图从 DRF 视图集禁用 PUT 方法,您可以创建一个自定义路由器:

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 模式文档将是正确的。

如何在 DRF 中禁用 ViewSet 的“ DELETE”方法

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

附言。这比显式指定所有必要的方法更可靠,因此忘记一些重要方法的可能性更小

附注。 默认情况下,DRF 具有 http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

虽然这篇文章已经发表了一段时间,但我突然发现实际上有一种方法可以禁用这些函数,你可以直接在 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 NameThisClassWhateverYouWantViewSet(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)

在 Django RestFramework 3.x.x 中,只需要通过向 as_view方法传递一个字典,就可以为 ModelViewSet启用每个希望启用的方法。在这个字典中,键必须包含请求类型(GET、 POST、 DELETE 等) ,值必须包含相应的方法名(列表、检索、更新等)。例如,假设您希望创建或读取 Sample模型,但不希望对其进行修改。这意味着您希望启用 listretrievecreate方法(并且希望禁用其他方法)

您所需要做的就是像下面这样向 urlpatterns添加路径:

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

正如你所看到的,在上面的路由设置中没有 deleteput请求,所以举个例子,如果你发送一个 put请求到 URL,它会用405 Method Not Allowed来响应你:

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

禁用视图集上的方法、保持 api 的一致性并返回有用的错误消息的最直接的方法是,对于您不想使用的任何方法,简单地引发 MethodNotAlallow 异常。对于像 GET 这样的映射为检索和列表并禁用列表的方法,您可以自定义错误消息,以指示 GET 只对 URL 上的查找值起作用。

from rest_framework.exceptions import MethodNotAllowed


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


def list(self, request):
raise MethodNotAllowed('GET', detail='Method "GET" not allowed without lookup')
def create(self, request):
raise MethodNotAllowed(method='POST')

这将返回 DRF 使用的格式的405状态码和 json 数据:

{'detail': 'Method "POST" not allowed.'}

我喜欢@pymen answer 的想法,但他的实施没有奏效。这个方法奏效了:

class SampleViewSet(viewsets.ModelViewSet):
http_method_names = [m for m in viewsets.ModelViewSet.http_method_names if m not in ['delete']]

这样做的好处是只做字面上的排除,而且很简单。虽然它看起来有点粗糙,但如果只是为了那一个 ViewSet,那么它可能正是您所需要的。

你可以写一个小装修师:

def http_methods_disable(*methods):
def decorator(cls):
cls.http_method_names = [method for method in cls.http_method_names if method not in methods]
return cls
return decorator

然后可以在不同的类别中使用:

@http_methods_disable('patch', 'delete')
class SampleViewSet(viewsets.ModelViewSet):
...


@http_methods_disable('patch')
class AnyViewSet(viewsets.ModelViewSet):
...

我更喜欢这样。

from rest_framework import viewsets, mixins


class ContentViewSet(mixins.CreateModelMixin, viewsets.ReadOnlyModelViewSet):
queryset = models.Content.objects.all()
serializer_class = serializers.ContentSerializer

ReadOnlyModelViewSet -这将只保留只读方法。

CreateModelMixin -这只允许创建新元素,即“ POST”请求。

所有其他方法,如“ PUT”,“ PATH”和“ DELETE”在上面的例子中被禁用。您可以根据需求使用 Mixin 启用各种方法。

Django-rest-Framework 中 Viewsets 的另一种方法是启用/禁用方法,下面是一个 api/urls.py 示例:

    user_list = UserViewSet.as_view({
'get': 'list'
})
user_detail = UserViewSet.as_view({
'get': 'retrieve'
'put': 'update',
'post': 'create',
'patch': 'partial_update',
'delete': 'destroy'
})




urlpatterns = [
path('users/', user_list, name='user-list'),
path('users/<int:pk>/', user_detail, name='user-detail')
]

View user _ list 只允许使用一个 get 方法,而 user _ Details 的所有方法都是活动的。

在 Django 4.0上测试

参考资料: 详情请浏览此网页

只要使用 GenericViewSet,就必须在使用它们之前显式地定义 HTTP 操作。