Tắt một phương thức trong ViewSet, django-rest-framework


124

ViewSets có các phương thức tự động để liệt kê, truy xuất, tạo, cập nhật, xóa, ...

Tôi muốn vô hiệu hóa một số trong số đó, và giải pháp tôi đưa ra có lẽ không phải là giải pháp tốt, vì OPTIONSvẫn nêu những giải pháp được cho phép.

Bất kỳ ý tưởng về cách làm điều này một cách đúng đắn?

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)

Câu trả lời:


250

Định nghĩa của ModelViewSetlà:

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

Vì vậy, thay vì mở rộng ModelViewSet, tại sao không chỉ sử dụng bất cứ thứ gì bạn cần? Ví dụ:

from rest_framework import viewsets, mixins

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

Với cách tiếp cận này, bộ định tuyến chỉ nên tạo các tuyến cho các phương thức được bao gồm.

Tham khảo :

ModelViewSet


@SunnySydeUp Bạn chỉ cần thử điều này ngay bây giờ và có vẻ như bộ định tuyến tạo ra tuyến đường cho chế độ xem danh sách, nhưng lỗi 404 vì ViewSet không biết cách xử lý yêu cầu. Đây có phải là những gì bạn mong đợi?
Steve Jalim

3
Bằng cách chỉ sử dụng các mixin bạn cần, bạn có thể tắt các phương thức GET, POST, PUT, DELETE nhưng tôi không thể tìm ra cách tắt phương thức PATCH đặc biệt nếu bạn đang sử dụng bộ định tuyến.
Muneeb Ahmad

3
@MuneebAhmad Phương thức PATCH được kích hoạt từ UpdateModelMixin. Nếu bạn muốn sử dụng bản cập nhật nhưng không phải bản vá, tôi hiện có thể nghĩ ra hai cách. Bạn có thể ghi đè các phương thức được phép trong dạng xem và xóa "bản vá" hoặc bạn có thể ghi đè partial_updatephương thức và cuộc gọi http_method_not_allowed(request, *args, **kwargs). Tôi đã không kiểm tra này vì vậy tôi không chắc chắn nếu nó hoạt động
SunnySydeUp

1
@JulioMarins Tôi đã thêm một tài liệu tham khảo. Tôi không chắc liệu đây có phải là điều bạn muốn hay không.
SunnySydeUp

1
Nếu ai đó muốn đặt chế độ xem chỉ đọc thì họ có thể sử dụng class SampleViewSet(viewsets.ReadOnlyModelViewSet).
Bikash kharel

133

Bạn có thể tiếp tục sử dụng viewsets.ModelViewSetvà xác định http_method_namestrên ViewSet của mình.

Thí dụ

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

Một khi bạn thêm http_method_names, bạn sẽ không thể làm putpatchnữa.

Nếu bạn muốn putnhưng không muốn patch, bạn có thể giữhttp_method_names = ['get', 'post', 'head', 'put']

Nội bộ, Chế độ xem DRF mở rộng từ Django CBV. Django CBV có một thuộc tính được gọi là http_method_names. Vì vậy, bạn cũng có thể sử dụng http_method_names với chế độ xem DRF.

[Shameless Plug]: Nếu câu trả lời này hữu ích, bạn sẽ thích loạt bài đăng của tôi về DRF tại https://www.agiliq.com/blog/2019/04/drf-polls/ .


16
Vấn đề với cách này là không có cách nào để vô hiệu hóa danh sách hoặc truy xuất. Phải vô hiệu hóa cả hai hay không
Fuad

1
Điều này đã không làm việc cho tôi, sau đó get và đầu tôi vẫn còn có thể làm một bài
runloop

Điều này phù hợp với tôi trên django 1.9. Giải pháp tuyệt vời. Người dùng có thể thực hiện yêu cầu GET theo cách khác có rủi ro không?
Ycon

Giải pháp FANTASTIC. Hoạt động tốt python3Django 1.10tốt.
Urda

2
Tôi thích cách tiếp cận này bởi vì tôi không thể thay đổi thừa kế của mixins bao gồm PATCH, nhưng không PUT vì họ đều là một thực hiện mixins.UpdateModelMixin
ThatsAMorais

5

Mặc dù bài đăng này đã được một thời gian, tôi đột nhiên phát hiện ra rằng thực sự của họ là một cách để tắt chức năng đó, bạn có thể chỉnh sửa trực tiếp trong views.py.

Nguồn: 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)

Đây nên là một cách thích hợp.
digitake

Tôi nghĩ HTTP_400_BAD_REQUEST sẽ thích hợp hơn ở đây nếu nó không liên quan đến auth.
Santiago Magariños

4

Nếu bạn đang cố gắng vô hiệu hóa phương thức PUT từ bộ xem DRF, bạn có thể tạo bộ định tuyến tùy chỉnh:

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

Bằng cách tắt phương thức trên bộ định tuyến, tài liệu lược đồ api của bạn sẽ chính xác.


Vì bản vá một phần không được triển khai chính xác trong DRF nên sẽ khôn ngoan hơn nếu xóa nó trên toàn cầu theo cách được mô tả ở đây
oden

1

Cách tắt phương thức "DELETE" cho ViewSet trong 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 Điều này đáng tin cậy hơn là chỉ định rõ ràng tất cả các phương thức cần thiết, vì vậy ít có khả năng bạn quên một số phương thức quan trọng OPTIONS, HEAD, v.v.

PPS theo mặc định DRF có http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']


Bạn không thể gọi supertrên cấp độ lớp học, không có self.
validname

0

Trong Django Rest Framework 3.xx, bạn có thể chỉ cần kích hoạt mọi phương thức bạn muốn được kích hoạt ModelViewSet, bằng cách chuyển từ điển cho as_viewphương thức. Trong từ điển này, khóa phải chứa loại yêu cầu (GET, POST, DELETE, v.v.) và giá trị phải chứa tên phương thức tương ứng (danh sách, truy xuất, cập nhật, v.v.). Ví dụ: giả sử bạn muốn Samplemô hình được tạo hoặc đọc nhưng bạn không muốn nó được sửa đổi. Vì vậy, nó có nghĩa là bạn muốn list, retrievecreate phương pháp được cho phép (và bạn muốn người khác bị vô hiệu hóa.)

Tất cả những gì bạn cần làm là thêm các đường dẫn urlpatternsnhư sau:

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

Như bạn có thể thấy không có deleteputyêu cầu trong cài đặt định tuyến ở trên, vì vậy, ví dụ: nếu bạn gửi một putyêu cầu đến url, nó sẽ trả lời bạn bằng 405 Method Not Allowed:

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.