Desabilite um método em um ViewSet, django-rest-framework

124

ViewSets têm métodos automáticos para listar, recuperar, criar, atualizar, excluir, ...

Eu gostaria de desabilitar alguns deles, e a solução que encontrei provavelmente não é boa, já que OPTIONSainda afirma aqueles como permitidos.

Alguma ideia de como fazer isso da maneira certa?

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
fonte

Respostas:

250

A definição de ModelViewSeté:

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

Então, em vez de estender ModelViewSet, por que não usar o que você precisa? Então, por exemplo:

from rest_framework import viewsets, mixins

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

Com essa abordagem, o roteador deve gerar apenas rotas para os métodos incluídos.

Referência :

ModelViewSet

SunnySydeUp
fonte
@SunnySydeUp Estou apenas tentando fazer isso agora e parece que o roteador gera a rota para uma exibição de lista, mas é 404 porque o ViewSet não sabe como lidar com a solicitação. É isso que você esperava?
Steve Jalim
3
Usando apenas os mixins que você precisa, você pode desabilitar os métodos GET, POST, PUT, DELETE, mas eu não consegui descobrir como desabilitar o método PATCH, especialmente se você estiver usando roteadores.
Muneeb Ahmad
3
@MuneebAhmad O método PATCH é habilitado no UpdateModelMixin. Se você quiser usar a atualização, mas não o patch, atualmente posso pensar em duas maneiras. Você pode substituir os métodos permitidos na visualização e remover "patch" ou pode substituir o partial_updatemétodo e chamar http_method_not_allowed(request, *args, **kwargs). Eu não testei isso, então não tenho certeza se funciona
SunnySydeUp
1
@JulioMarins adicionei uma referência. Não tenho certeza se isso é o que você queria.
SunnySydeUp
1
Se alguém quiser criar um conjunto de visualizações somente leitura, poderá usá-lo class SampleViewSet(viewsets.ReadOnlyModelViewSet).
Bikash Kharel
133

Você pode continuar usando viewsets.ModelViewSete definir http_method_namesem seu ViewSet.

Exemplo

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

Depois de adicionar http_method_names, você não será capaz de fazer pute patchmais.

Se você quiser, putmas não quiser patch, você pode manterhttp_method_names = ['get', 'post', 'head', 'put']

Internamente, as visualizações DRF estendem-se do Django CBV. Django CBV tem um atributo chamado http_method_names. Portanto, você também pode usar http_method_names com visualizações DRF.

[Shameless Plug]: Se esta resposta foi útil, você gostará da minha série de postagens sobre DRF em https://www.agiliq.com/blog/2019/04/drf-polls/ .

Akshar Raaj
fonte
16
O problema com essa maneira é a impossibilidade de desabilitar a lista ou a recuperação. Tem que desativar ambos ou nenhum
Fuad
1
Isso não funcionou para mim, depois de incluir get e head, eu ainda era capaz de fazer um post
RunLoop
Isso funciona para mim no django 1.9. Ótima solução. Existe o risco de os usuários fazerem uma solicitação GET de outra maneira?
Ycon
Solução FANTÁSTICA. Funciona python3e Django 1.10muito bem.
Urda
2
Eu prefiro essa abordagem porque não pude alterar a herança dos mixins para incluir PATCH, mas não PUT porque ambos são uma implementação de mixins.UpdateModelMixin
ThatsAMorais
5

Embora já faça um bom tempo para este post, de repente descobri que, na verdade, é uma maneira de desabilitar essas funções, você pode editá-la diretamente no 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)
W Kenny
fonte
Essa deve ser a maneira preferível.
digitake
Acho que HTTP_400_BAD_REQUEST seria mais apropriado aqui se não estiver relacionado à autenticação.
Santiago Magariños
4

Se você está tentando desativar o método PUT de um conjunto de visualizações DRF, pode criar um roteador 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

Ao desabilitar o método no roteador, a documentação do seu esquema de API estará correta.

storn
fonte
Como o patch parcial não está implementado corretamente no DRF, seria sensato removê-lo globalmente da maneira descrita aqui
oden
1

Como desativar o método "DELETE" para ViewSet em 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 Isso é mais confiável do que especificar explicitamente todos os métodos necessários, então há menos chance de esquecer alguns dos métodos importantes OPTIONS, HEAD, etc.

PPS por padrão DRF tem http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

pymen
fonte
Você não pode ligar superno nível da classe, não há self.
validname
0

No Django Rest Framework 3.xx você pode simplesmente habilitar cada método para o qual deseja habilitar ModelViewSet, passando um dicionário para o as_viewmétodo. Neste dicionário, a chave deve conter o tipo de solicitação (GET, POST, DELETE, etc) e o valor deve conter o nome do método correspondente (list, retrieve, update, etc). Por exemplo, digamos que você queira que o Samplemodelo seja criado ou lido, mas não queira que ele seja modificado. Então isso significa que você quer list, retrievee createmétodo seja permitir (e você quer que os outros para ser desativado.)

Tudo que você precisa fazer é adicionar caminhos urlpatternscomo estes:

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

Como você pode ver que não há é deletee putsolicitação na acima configurações de roteamento, por exemplo, se você envia uma putsolicitação para o URL, resposta que você com 405 Method Not Allowed:

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