Disabilita un metodo in un ViewSet, django-rest-framework


125

ViewSets avere metodi automatici per elencare, recuperare, creare, aggiornare, eliminare, ...

Vorrei disabilitare alcuni di questi e la soluzione che ho trovato probabilmente non è buona, dal momento OPTIONSche indica ancora quelli consentiti.

Qualche idea su come farlo nel modo giusto?

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)

Risposte:


250

La definizione di ModelViewSetè:

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

Quindi, invece di estendere ModelViewSet, perché non usare semplicemente ciò di cui hai bisogno? Quindi per esempio:

from rest_framework import viewsets, mixins

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

Con questo approccio, il router dovrebbe generare solo percorsi per i metodi inclusi.

Riferimento :

ModelViewSet


@SunnySydeUp Ci sto provando ora e sembra che il router generi il percorso per una visualizzazione elenco, ma funziona in 404 perché ViewSet non sa come gestire la richiesta. È questo quello che ti aspettavi?
Steve Jalim

3
Usando solo i mixin di cui hai bisogno puoi disabilitare i metodi GET, POST, PUT, DELETE ma non sono riuscito a scoprire come disabilitare il metodo PATCH specialmente se stai usando i router.
Muneeb Ahmad

3
@MuneebAhmad Il metodo PATCH è abilitato da UpdateModelMixin. Se vuoi usare l'aggiornamento ma non la patch, al momento posso pensare a due modi. Puoi sovrascrivere i metodi consentiti nella vista e rimuovere "patch" oppure puoi sovrascrivere il partial_updatemetodo e chiamare http_method_not_allowed(request, *args, **kwargs). Non l'ho provato, quindi non sono sicuro che funzioni
SunnySydeUp

1
@ JulioMarins ho aggiunto un riferimento. Non sono sicuro se questo è quello che volevi però.
SunnySydeUp

1
Se qualcuno desidera creare un set di visualizzazione di sola lettura, può utilizzare class SampleViewSet(viewsets.ReadOnlyModelViewSet).
Bikash kharel

133

Potresti continuare a usare viewsets.ModelViewSete definire http_method_namessul tuo ViewSet.

Esempio

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

Una volta aggiunto http_method_names, non sarai più in grado di fare pute patchpiù.

Se vuoi putma non vuoi patch, puoi tenerlohttp_method_names = ['get', 'post', 'head', 'put']

Internamente, le viste DRF si estendono da Django CBV. Django CBV ha un attributo chiamato http_method_names. Quindi puoi usare http_method_names anche con le viste DRF.

[Shameless Plug]: Se questa risposta è stata utile, ti piacerà la mia serie di post su DRF su https://www.agiliq.com/blog/2019/04/drf-polls/ .


16
Il problema con questo modo non è il modo per disabilitare l'elenco o il recupero. Devo disabilitare entrambi o nessuno dei due
Fuad

1
Questo non ha funzionato per me, dopo aver incluso get and head ero ancora in grado di fare un post
RunLoop

Questo funziona per me su django 1.9. Ottima soluzione. C'è il rischio che gli utenti possano eseguire una richiesta GET in un altro modo?
Ycon

Soluzione FANTASTICA. Funziona python3e va Django 1.10bene.
Urda

2
Preferisco questo approccio perché non ho potuto modificare l'eredità dei mixin per includere PATCH, ma non PUT perché sono entrambi un'implementazione di mixins.UpdateModelMixin
ThatsAMorais

5

Anche se è passato un po 'di tempo per questo post, ho improvvisamente scoperto che in realtà il loro è un modo per disabilitare quelle funzioni, puoi modificarlo direttamente in views.py.

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

Questo dovrebbe essere un modo preferibile.
digitake

Penso che HTTP_400_BAD_REQUEST sarebbe più appropriato qui se non è correlato ad auth.
Santiago Magariños

4

Se stai tentando di disabilitare il metodo PUT da un set di visualizzazione DRF, puoi creare un router personalizzato:

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

Disabilitando il metodo sul router, la documentazione dello schema api sarà corretta.


Poiché la patch parziale non è implementata correttamente all'interno di DRF, sarebbe saggio rimuoverla globalmente nel modo descritto qui
oden

1

Come disabilitare il metodo "DELETE" per 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']]

PS Questo è più affidabile che specificare esplicitamente tutti i metodi necessari, quindi ci sono meno possibilità di dimenticare alcuni dei metodi importanti OPZIONI, TESTA, ecc.

PPS per impostazione predefinita DRF ha http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']


Non puoi chiamare supera livello di classe, no self.
validname

0

In Django Rest Framework 3.xx puoi semplicemente abilitare ogni metodo per cui vuoi essere abilitato ModelViewSet, passando un dizionario a as_viewmetodo. In questo dizionario, la chiave deve contenere il tipo di richiesta (GET, POST, DELETE, ecc.) E il valore deve contenere il nome del metodo corrispondente (list, retrieve, update, ecc.). Ad esempio, supponiamo che tu voglia Samplecreare o leggere un modello ma non vuoi che venga modificato. Quindi significa che si desidera list, retrievee createmetodo per essere consentire (e si vuole altri ad essere disabilitata.)

Tutto quello che devi fare è aggiungere percorsi urlpatternscome questi:

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

Come si può vedere non c'è deletee putrichiesta al precedente impostazioni di routing, così per esempio se si invia un putrichiesta all'URL, ti risposta con 405 Method Not Allowed:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.