Nonaktifkan metode dalam ViewSet, django-rest-framework

125

ViewSets memiliki metode otomatis untuk mendaftar, mengambil, membuat, memperbarui, menghapus, ...

Saya ingin menonaktifkan beberapa di antaranya, dan solusi yang saya hasilkan mungkin tidak bagus, karena OPTIONSmasih menyatakan yang diizinkan.

Ada ide tentang bagaimana melakukan ini dengan cara yang benar?

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
sumber

Jawaban:

250

Definisi dari ModelViewSetadalah:

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

Jadi, daripada memperluas ModelViewSet, mengapa tidak menggunakan apa pun yang Anda butuhkan? Jadi contohnya:

from rest_framework import viewsets, mixins

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

Dengan pendekatan ini, router seharusnya hanya menghasilkan rute untuk metode yang disertakan.

Referensi :

ModelViewSet

SunnySydeUp
sumber
@SunnySydeUp Hanya mencoba ini sekarang dan tampaknya router menghasilkan rute untuk tampilan daftar, tetapi 404s karena ViewSet tidak tahu bagaimana menangani permintaan. Apakah ini yang Anda harapkan?
Steve Jalim
3
Dengan hanya menggunakan mixins yang Anda butuhkan, Anda dapat menonaktifkan Metode GET, POST, PUT, DELETE tetapi saya tidak dapat menemukan cara menonaktifkan metode PATCH khususnya jika Anda menggunakan router.
Muneeb Ahmad
3
@MuneebAhmad Metode PATCH diaktifkan dari UpdateModelMixin. Jika Anda ingin menggunakan update tetapi bukan patch, saat ini saya dapat memikirkan dua cara. Anda dapat mengganti metode yang diizinkan dalam tampilan dan menghapus "patch" atau Anda dapat mengganti partial_updatemetode dan memanggil http_method_not_allowed(request, *args, **kwargs). Saya belum menguji ini jadi saya tidak yakin apakah itu berhasil
SunnySydeUp
1
@JulioMarins Saya telah menambahkan referensi. Saya tidak yakin apakah ini yang Anda inginkan.
SunnySydeUp
1
Jika seseorang ingin membuat viewset hanya-baca maka mereka dapat menggunakannya class SampleViewSet(viewsets.ReadOnlyModelViewSet).
Bikash kharel
133

Anda dapat terus menggunakan viewsets.ModelViewSetdan menentukan http_method_namesdi ViewSet Anda.

Contoh

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

Setelah Anda menambahkan http_method_names, Anda tidak akan dapat melakukan putdan patchlagi.

Jika Anda mau puttapi tidak mau patch, Anda bisa menyimpannyahttp_method_names = ['get', 'post', 'head', 'put']

Secara internal, Tampilan DRF meluas dari Django CBV. Django CBV memiliki atribut yang disebut http_method_names. Jadi, Anda juga dapat menggunakan http_method_names dengan tampilan DRF.

[Shameless Plug]: Jika jawaban ini bermanfaat, Anda akan menyukai rangkaian posting saya di DRF di https://www.agiliq.com/blog/2019/04/drf-polls/ .

Akshar Raaj
sumber
16
Masalah dengan cara ini adalah tidak ada cara untuk menonaktifkan daftar atau mengambil. Harus menonaktifkan keduanya atau tidak keduanya
Fuad
1
Ini tidak berhasil untuk saya, setelah memasukkan get and head saya masih bisa melakukan posting
RunLoop
Ini bekerja untuk saya di django 1.9. Solusi bagus. Apakah ada risiko pengguna dapat melakukan permintaan GET dengan cara lain?
Ycon
Solusi fantastis. Bekerja python3dan Django 1.10baik-baik saja.
Urda
2
Saya lebih suka pendekatan ini karena saya tidak dapat mengubah warisan mixin untuk menyertakan PATCH, tetapi bukan PUT karena keduanya merupakan implementasi dari mixins.UpdateModelMixin
ThatsAMorais
5

Meskipun sudah lama untuk posting ini, saya tiba-tiba menemukan bahwa sebenarnya mereka adalah cara untuk menonaktifkan fungsi tersebut, Anda dapat mengeditnya langsung di views.py.

Sumber: 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)
W Kenny
sumber
Ini harus menjadi cara yang lebih disukai.
digitake
Saya pikir HTTP_400_BAD_REQUEST akan lebih sesuai di sini jika tidak terkait dengan auth.
Santiago Magariños
4

Jika Anda mencoba menonaktifkan metode PUT dari kumpulan tampilan DRF, Anda dapat membuat router kustom:

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

Dengan menonaktifkan metode di router, dokumentasi skema api Anda akan benar.

storn
sumber
Karena tambalan parsial tidak diterapkan dengan benar dalam DRF, sebaiknya hapus secara global dengan cara yang dijelaskan di sini
oden
1

Cara menonaktifkan metode "DELETE" untuk ViewSet di 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 Ini lebih dapat diandalkan daripada secara eksplisit menentukan semua metode yang diperlukan, jadi kecil kemungkinannya untuk melupakan beberapa metode penting OPTIONS, HEAD, dll.

PPS secara default memiliki DRF http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

pymen
sumber
Anda tidak dapat menelepon superdi tingkat kelas, tidak ada self.
validname
0

Dalam Django Rest Framework 3.xx Anda dapat dengan mudah mengaktifkan setiap metode yang ingin Anda aktifkan ModelViewSet, dengan meneruskan kamus ke as_viewmetode. Dalam kamus ini, kunci harus berisi jenis permintaan (GET, POST, DELETE, dll) dan nilainya harus berisi nama metode yang sesuai (daftar, ambil, perbarui, dll). Misalnya Anda ingin Samplemodel dibuat atau dibaca tetapi Anda tidak ingin model dimodifikasi. Jadi itu berarti Anda ingin list, retrievedan createmetode untuk diaktifkan (dan Anda ingin orang lain dinonaktifkan.)

Yang perlu Anda lakukan adalah menambahkan jalur urlpatternsseperti ini:

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

Seperti yang Anda lihat, tidak ada deletedan putpermintaan di setelan perutean di atas, jadi misalnya jika Anda mengirim putpermintaan ke url, ia akan membalas Anda dengan 405 Method Not Allowed:

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