Adam
Adam

Reputation: 2552

Method Delete Not Allowed - destroy() method Django

I have looked online for all possible solutions to this recurring question, but nothing I have tried works.

I have a view set that retrieves and creates certain information. For reference, retrieving and creating that information is specific to each user. If a user has already created an entry, they are not allowed to create another.

The two methods for retrieving and creating right now are as follows:

class MyViewSet(ModelViewSet):
  queryset = MyModel.objects.all()
  serializer_class = MySerializer

  def get_queryset(self):
    return self.queryset.filter(user=self.request.user.username)

  def create(self, request, *args, **kwargs):
    result = MyModel.objects.filter(user=request.user.username)
    if (result):
      return Response(status=405)

    # Otherwise, create an entry for that user

The endpoint to both of these operations don't include any arguments in the URL. In other words, they are GET /my-endpoint/ and POST /my-endpoint/ (since each operation is specific to a user)

Right now, I am trying to add a DELETE operation using destroy(). I understand that a destroy() sometimes requires a pk, but from what I've seen online, you can bypass that by specifying pk=None as I've done below. As I mentioned before, my-endpoint/ does not require any arguments or parameters in the URL so deleting an entry for a given user can be done by calling DELETE my-endpoint/.

As a result, I've got:

def destroy(self, request, pk=None):
  # This isn't being called when hitting DELETE my-endpoint/. Instead, I get an error as below

[ "detail": "Method "DELETE" not allowed." ]

How can I resolve this knowing that I don't pass any arguments into my-endpoint/ for DELETE?

Upvotes: 1

Views: 2084

Answers (1)

Brian Destura
Brian Destura

Reputation: 12068

You get this error because omitting the arguments in the URL will cause the router to fetch either create or list (which is POST and GET respectively). But seeing that the request method is DELETE, it will complain because the only thing available for that endpoint is, as discussed, only POST and GET.

If you really want to support DELETE on the base url, you will have to override the mapping of routers that build the urls (from the link above). But probably the simplest way is to use actions to create a new endpoint that deletes without needing a pk:

class MyViewSet(ModelViewSet):
    ...
    @action(detail=False, methods=['DELETE'], url_path='delete')
    def my_custom_destroy(self, request, *args, **kwargs):
        # will be called by DELETE my-endpoint/delete

Upvotes: 1

Related Questions