Désactiver une méthode dans un ViewSet, django-rest-framework

125

ViewSets ont des méthodes automatiques pour lister, récupérer, créer, mettre à jour, supprimer, ...

Je voudrais désactiver certains d'entre eux, et la solution que j'ai proposée n'est probablement pas la bonne, car les OPTIONSindique toujours comme autorisés.

Une idée sur la manière de procéder de la bonne manière?

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
la source

Réponses:

250

La définition de ModelViewSetest:

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

Alors plutôt que d'étendre ModelViewSet, pourquoi ne pas simplement utiliser ce dont vous avez besoin? Donc par exemple:

from rest_framework import viewsets, mixins

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

Avec cette approche, le routeur ne doit générer des routes que pour les méthodes incluses.

Référence :

ModelViewSet

SunnySydeUp
la source
@SunnySydeUp Juste en essayant ceci maintenant et il semble que le routeur génère la route pour une vue de liste, mais cela 404s parce que le ViewSet ne sait pas comment gérer la demande. Est-ce ce à quoi vous vous attendiez?
Steve Jalim du
3
En n'utilisant que les mixins dont vous avez besoin, vous pouvez désactiver les méthodes GET, POST, PUT, DELETE mais je n'ai pas pu découvrir comment désactiver la méthode PATCH spécialement si vous utilisez des routeurs.
Muneeb Ahmad
3
@MuneebAhmad La méthode PATCH est activée à partir du UpdateModelMixin. Si vous souhaitez utiliser la mise à jour mais pas le patch, je peux actuellement penser à deux façons. Vous pouvez soit remplacer les méthodes autorisées dans la vue et supprimer «patch», soit remplacer la partial_updateméthode et appeler http_method_not_allowed(request, *args, **kwargs). Je n'ai pas testé cela, donc je ne suis pas sûr que cela fonctionne
SunnySydeUp
1
@JulioMarins J'ai ajouté une référence. Je ne sais pas si c'est ce que vous vouliez.
SunnySydeUp
1
Si quelqu'un souhaite créer un ensemble de vues en lecture seule, il peut l'utiliser class SampleViewSet(viewsets.ReadOnlyModelViewSet).
Bikash kharel
133

Vous pouvez continuer à utiliser viewsets.ModelViewSetet à définir http_method_namessur votre ViewSet.

Exemple

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

Une fois que vous avez ajouté http_method_names, vous ne pourrez plus faire putet patchplus.

Si tu veux putmais ne veux pas patch, tu peux garderhttp_method_names = ['get', 'post', 'head', 'put']

En interne, les vues DRF s'étendent de Django CBV. Django CBV a un attribut appelé http_method_names. Vous pouvez donc également utiliser http_method_names avec les vues DRF.

[Shameless Plug]: Si cette réponse vous a été utile, vous aimerez ma série d'articles sur DRF à l' adresse https://www.agiliq.com/blog/2019/04/drf-polls/ .

Akshar Raaj
la source
16
Le problème avec cette méthode n'est aucun moyen de désactiver la liste ou de récupérer. Doit désactiver les deux ou ni l'un ni l'autre
Fuad
1
Cela n'a pas fonctionné pour moi, après avoir inclus get and head, je pouvais toujours faire un post
RunLoop
Cela fonctionne pour moi sur django 1.9. Excellente solution. Existe-t-il un risque que les utilisateurs puissent faire une demande GET d'une autre manière?
Ycon
Solution FANTASTIQUE. Fonctionne python3et Django 1.10très bien.
Urda
2
Je préfère cette approche car je ne pourrais pas changer l'héritage des mixins pour inclure PATCH, mais pas PUT car ils sont tous les deux une implémentation de mixins.UpdateModelMixin
ThatsAMorais
5

Bien que cela fasse un moment pour cet article, j'ai soudainement découvert que c'était en fait un moyen de désactiver ces fonctions, vous pouvez le modifier directement dans le fichier views.py.

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 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
la source
Cela devrait être une méthode préférable.
digitake le
Je pense que HTTP_400_BAD_REQUEST serait plus approprié ici s'il n'est pas lié à auth.
Santiago Magariños
4

Si vous essayez de désactiver la méthode PUT à partir d'un ensemble de vues DRF, vous pouvez créer un routeur personnalisé:

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

En désactivant la méthode sur le routeur, la documentation de votre schéma d'API sera correcte.

étourdi
la source
Comme le correctif partiel n'est pas correctement implémenté dans DRF, il serait sage de le supprimer globalement de la manière décrite ici
oden
1

Comment désactiver la méthode "DELETE" pour ViewSet dans 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 Ceci est plus fiable que de spécifier explicitement toutes les méthodes nécessaires, il y a donc moins de chance d'oublier certaines des méthodes importantes OPTIONS, HEAD, etc.

PPS par défaut DRF a http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

pymen
la source
Vous ne pouvez pas appeler superau niveau de la classe, il n'y a pas self.
valide
0

Dans Django Rest Framework 3.xx, vous pouvez simplement activer chaque méthode pour laquelle vous souhaitez activer ModelViewSet, en passant un dictionnaire à as_viewmethod. Dans ce dictionnaire, la clé doit contenir le type de requête (GET, POST, DELETE, etc.) et la valeur doit contenir le nom de la méthode correspondante (lister, récupérer, mettre à jour, etc.). Par exemple, disons que vous voulez que le Samplemodèle soit créé ou lu mais que vous ne voulez pas qu'il soit modifié. Donc , cela signifie que vous voulez list, retrieveet la createméthode pour être permettre (et vous voulez que les autres sont désactivés.)

Tout ce que vous avez à faire est d'ajouter des chemins pour urlpatternsaimer ceux-ci:

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

Comme vous pouvez le voir il n'y a pas deleteet putdemande au- dessus des paramètres de routage, donc par exemple si vous envoyez une putdemande à l'URL, il vous réponse avec 405 Method Not Allowed:

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