Reputation: 1226
I'm using Django Rest Framework and want to be able to delete a Content instance via DELETE
to /api/content/<int:pk>/
. I don't want to implement any method to respond to GET
requests.
When I include a .retrieve()
method as follows, the DELETE
request works:
class ContentViewSet(GenericViewSet):
def get_queryset(self):
return Content.objects.filter(user=self.request.user)
def retrieve(self, request, pk=None):
pass #this works, but I don't want .retrieve() at all
def delete(self, request, pk=None):
content = self.get_object()
#look up some info info here
content.delete()
return Response('return some info')
If I replace .retrieve()
with RetrieveModelMixin
it also works. However, if I remove both of these, which is what want to do, I get the following error.
django.urls.exceptions.NoReverseMatch: Reverse for 'content-detail' not found. 'content-detail' is not a valid view function or pattern name.
I haven't tested, but I assume the same thing would happen with PUT
and PATCH
.
My questions are:
DELETE
without implementing a .retrieve()
method, and.retrieve()
implemented?UPDATE: Failing test and complete error traceback caused by removing .retrieve()
method
from rest_framework.test import APITestCase, APIClient
from myapp.models import Content
class ContentTestCase(APITestCase):
def setUp(self):
self.content = Content.objects.create(title='New content')
self.client = APIClient()
def test_DELETE_content(self):
url = reverse('content-detail', kwargs={'pk':self.content.pk})
response = self.client.delete(url)
self.assertEqual(response.status_code, 200)
Results in:
Traceback (most recent call last):
File "myproject/myapp/tests.py", line 548, in test_DELETE_content
url = reverse('content-detail', kwargs={'pk':self.content})
File "python3.6/site-packages/rest_framework/reverse.py", line 50, in reverse
url = _reverse(viewname, args, kwargs, request, format, **extra)
File "python3.6/site-packages/rest_framework/reverse.py", line 63, in _reverse
url = django_reverse(viewname, args=args, kwargs=kwargs, **extra)
File "python3.6/site-packages/django/urls/base.py", line 90, in reverse
return iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs))
File "python3.6/site-packages/django/urls/resolvers.py", line 636, in _reverse_with_prefix
raise NoReverseMatch(msg)
django.urls.exceptions.NoReverseMatch: Reverse for 'content-detail' not found. 'content-detail' is not a valid view function or pattern name.
Upvotes: 2
Views: 4141
Reputation: 84
Wild guess here but did you use a SimpleRouter
or a DefaultRouter
to build your urlpatterns
?
If so, that's your problem. The router uses a viewset and expects to have all methods implemented. More info here
What you can do is just add your url
to urlpatterns
like you would normally do on django using the .as_view()
method.
Upvotes: 1
Reputation: 88509
- How can I allow DELETE without implementing a
.retrieve()
method?
Just remove the retrieve()
method from the view class. Which means, the GenericViewSet
doesn't provide any HTTP Actions unless it's defined in your class.
So, the following will be your code snippet,
class ContentViewSet(GenericViewSet):
def get_queryset(self):
return Content.objects.filter(user=self.request.user)
def delete(self, request, pk=None):
content = self.get_object()
# look up some info info here
content.delete()
return Response('return some info')
or you could use mixin classes
here,
from rest_framework.mixins import DestroyModelMixin
class ContentViewSet(DestroyModelMixin, GenericViewSet):
def get_queryset(self):
return Content.objects.filter(user=self.request.user)
- Why can't DRF create the urlconf without
.retrieve()
implemented?
I'm not sure how you've defined your URLs. When I tried with DRF Router, it's only creating the URL conf for defined actions.
You've got GET
and DELETE
actions on your end-point because of you'd defined the retrieve()
method in your view class.
Hope this help :)
Upvotes: 2
Reputation: 1226
My solution for part 1. is to include the mixin but restrict the http_method_names
:
class ContentViewSet(RetrieveModelMixin, GenericViewSet):
http_method_names = ['delete']
...
However, I still don't know why I have to include RetrieveModelMixin
at all.
Upvotes: 0