Deshabilitar un método en un ViewSet, django-rest-framework

124

ViewSets tienen métodos automáticos para listar, recuperar, crear, actualizar, eliminar, ...

Me gustaría deshabilitar algunos de ellos, y la solución que se me ocurrió probablemente no sea buena, ya que OPTIONStodavía los indica como permitidos.

¿Alguna idea de cómo hacer esto de la manera correcta?

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
fuente

Respuestas:

250

La definición de ModelViewSetes:

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

Entonces, en lugar de extender ModelViewSet, ¿por qué no usar lo que necesite? Así por ejemplo:

from rest_framework import viewsets, mixins

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

Con este enfoque, el enrutador solo debe generar rutas para los métodos incluidos.

Referencia :

ModelViewSet

SunnySydeUp
fuente
@SunnySydeUp Intento esto ahora y parece que el enrutador genera la ruta para una vista de lista, pero es 404 porque ViewSet no sabe cómo manejar la solicitud. ¿Es esto lo que esperabas?
Steve Jalim
3
Al usar solo los mixins que necesita, puede deshabilitar los métodos GET, POST, PUT, DELETE, pero no pude averiguar cómo deshabilitar el método PATCH especialmente si está utilizando enrutadores.
Muneeb Ahmad
3
@MuneebAhmad El método PATCH se habilita desde el UpdateModelMixin. Si desea utilizar la actualización pero no el parche, actualmente puedo pensar en dos formas. Puede anular los métodos permitidos en la vista y eliminar "parche" o puede anular el partial_updatemétodo y llamar http_method_not_allowed(request, *args, **kwargs). No lo he probado, así que no estoy seguro de si funciona
SunnySydeUp
1
@JulioMarins He agregado una referencia. Sin embargo, no estoy seguro de si esto es lo que querías.
SunnySydeUp
1
Si alguien quiere crear un conjunto de vistas de solo lectura, puede usar class SampleViewSet(viewsets.ReadOnlyModelViewSet).
Bikash kharel
133

Puede seguir usando viewsets.ModelViewSety definir http_method_namesen su ViewSet.

Ejemplo

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

Una vez que agregue http_method_names, no podrá hacer puty patchmás.

Si quieres putpero no quieres patch, puedes quedartehttp_method_names = ['get', 'post', 'head', 'put']

Internamente, las vistas DRF se extienden desde Django CBV. Django CBV tiene un atributo llamado http_method_names. Por lo tanto, también puede usar http_method_names con vistas DRF.

[Shameless Plug]: Si esta respuesta fue útil, le gustará mi serie de publicaciones sobre DRF en https://www.agiliq.com/blog/2019/04/drf-polls/ .

Akshar Raaj
fuente
16
El problema con esta forma no es la forma de deshabilitar ninguna lista o recuperar. Tengo que deshabilitar ambos o ninguno
Fuad
1
Esto no funcionó para mí, después de incluir get y head, todavía pude hacer una publicación
RunLoop
Esto me funciona en django 1.9. Gran solucion ¿Existe el riesgo de que los usuarios puedan realizar una solicitud GET de otra manera?
Ycon
Solución FANTÁSTICA. Funciona python3y Django 1.10está bien.
Urda
2
Prefiero este enfoque porque no pude cambiar la herencia de mixins para incluir PATCH, pero no PUT porque ambos son una implementación de mixins.UpdateModelMixin
ThatsAMorais
5

Aunque ha pasado un tiempo para esta publicación, de repente descubrí que en realidad hay una forma de deshabilitar esa función, puede editarla directamente en views.py.

Fuente: 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
fuente
Esta debería ser una forma preferible.
digitake
Creo que HTTP_400_BAD_REQUEST sería más apropiado aquí si no está relacionado con la autenticación.
Santiago Magariños
4

Si está intentando deshabilitar el método PUT desde un conjunto de vistas DRF, puede crear un enrutador personalizado:

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

Al deshabilitar el método en el enrutador, la documentación de su esquema de api será correcta.

estornudar
fuente
Como el parche parcial no se implementa correctamente dentro de DRF, sería prudente eliminarlo globalmente de la forma descrita aquí
oden
1

Cómo deshabilitar el método "DELETE" para ViewSet en DRF

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

PD: Esto es más confiable que especificar explícitamente todos los métodos necesarios, por lo que hay menos posibilidades de olvidar algunos de los métodos importantes OPTIONS, HEAD, etc.

PPS por defecto DRF tiene http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

pymen
fuente
No puedes llamar supera nivel de clase, no hay self.
validname
0

En Django Rest Framework 3.xx, simplemente puede habilitar cada método para el que desea habilitar ModelViewSet, pasando un diccionario a as_viewmétodo. En este diccionario, la clave debe contener el tipo de solicitud (GET, POST, DELETE, etc.) y el valor debe contener el nombre del método correspondiente (listar, recuperar, actualizar, etc.). Por ejemplo, digamos que desea Sampleque se cree o lea el modelo, pero no desea que se modifique. Entonces significa que quieres list, retrieveycreate método sea habilitar (y desea a otros a ser desactivada.)

Todo lo que necesita hacer es agregar rutas urlpatternscomo estas:

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

Como puede ver, no hay una solicitud deletey puten la configuración de enrutamiento anterior, por ejemplo, si envía una putsolicitud a la URL, le responde con 405 Method Not Allowed:

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