Reputation: 2552
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
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