问题:在django-rest-framework中禁用ViewSet中的方法

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)

ViewSets have automatic methods to list, retrieve, create, update, delete, …

I would like to disable some of those, and the solution I came up with is probably not a good one, since OPTIONS still states those as allowed.

Any idea on how to do this the right way?

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)

回答 0

的定义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):
    ...

使用这种方法,路由器应该只为所包含的方法生成路由。

参考

模型视图集

The definition of ModelViewSet is:

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

So rather than extending ModelViewSet, why not just use whatever you need? So for example:

from rest_framework import viewsets, mixins

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

With this approach, the router should only generate routes for the included methods.

Reference:

ModelViewSet


回答 1

您可以继续使用viewsets.ModelViewSethttp_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,你将无法做到putpatch了。

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

在内部,DRF视图从Django CBV扩展。Django CBV具有一个名为http_method_names的属性。因此,您也可以在DRF视图中使用http_method_names。

[Shameless Plug]:如果此答案有用,您将喜欢我在DRF上的系列文章,网址https://www.agiliq.com/blog/2019/04/drf-polls/

You could keep using viewsets.ModelViewSet and define http_method_names on your ViewSet.

Example

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

Once you add http_method_names, you will not be able to do put and patch anymore.

If you want put but don’t want patch, you can keep http_method_names = ['get', 'post', 'head', 'put']

Internally, DRF Views extend from Django CBV. Django CBV has an attribute called http_method_names. So you can use http_method_names with DRF views too.

[Shameless Plug]: If this answer was helpful, you will like my series of posts on DRF at https://www.agiliq.com/blog/2019/04/drf-polls/.


回答 2

尽管这篇文章已经有一段时间了,但我突然发现实际上它们是禁用这些功能的一种方法,您可以直接在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)

Although it’s been a while for this post, I suddenly found out that actually there is a way to disable those functions, you can edit it in the views.py directly.

Source: 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)

回答 3

如果尝试从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模式文档将是正确的。

If you are trying to disable the PUT method from a DRF viewset, you can create a custom router:

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

By disabling the method at the router, your api schema documentation will be correct.


回答 4

如何在DRF中为ViewSet禁用“删除”方法

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等

默认情况下,DPS的PPS具有 http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

How to disable “DELETE” method for ViewSet in DRF

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

P.S. This is more reliable than explicitly specifying all the necessary methods, so there is less chance of forgetting some of important methods OPTIONS, HEAD, etc

P.P.S. by default DRF has http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']


回答 5

在Django Rest Framework 3.xx中,您可以ModelViewSet通过将字典传递给as_view方法来简单地启用要启用的每个方法。在此字典中,键必须包含请求类型(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'
}))

如您所见,上述路由设置中没有no deleteputrequest,因此例如,如果您将put请求发送到url,它将以405响应您Method Not Allowed

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

In Django Rest Framework 3.x.x you can simply enable every each method you want to be enabled for ModelViewSet, by passing a dictionary to as_view method. In this dictionary, the key must contain request type (GET, POST, DELETE, etc) and the value must contain corresponding method name (list, retrieve, update, etc). For example let say you want Sample model to be created or read but you don’t want it to be modified. So it means you want list, retrieve and create method to be enable (and you want others to be disabled.)

All you need to do is to add paths to urlpatterns like these:

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

As you can see there’s no delete and put request in above routing settings, so for example if you send a put request to the url, it response you with 405 Method Not Allowed:

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

回答 6

如果您打算禁用放置/发布/销毁方法,则可以使用

viewsets.ReadOnlyModelViewSet https://www.django-rest-framework.org/tutorial/6-viewsets-and-routers/#refactoring-to-use-viewsets

If you are planning to disable put/post/destroy methods, you can use

viewsets.ReadOnlyModelViewSet https://www.django-rest-framework.org/tutorial/6-viewsets-and-routers/#refactoring-to-use-viewsets


声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。