Django Rest Framework:在GenericAPIView上使用DELETE而不实现Retrieve

时间:2019-05-31 00:46:31

标签: django django-rest-framework

我正在使用Django Rest Framework,并且希望能够通过DELETE/api/content/<int:pk>/删除Content实例。我不想要实现任何方法来响应GET请求。

当我包含如下的.retrieve()方法时,DELETE请求起作用

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')

如果我将.retrieve()替换为RetrieveModelMixin,它也会起作用。但是,如果我同时删除了这两个选项,则会收到以下错误消息。

  

django.urls.exceptions.NoReverseMatch:找不到“内容详细信息”的反向内容。 “ content-detail”不是有效的视图函数或模式名称。

我还没有测试,但是我假设PUTPATCH也会发生同样的事情。

我的问题是:

  1. 如何在不实现DELETE方法的情况下允许.retrieve(),并且
  2. 为什么在未实施.retrieve()的情况下DRF无法创建urlconf?

更新:由于删除.retrieve()方法而导致测试失败并完成了错误回溯

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)

结果:

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.

3 个答案:

答案 0 :(得分:1)

  
      
  1. 如何在不实现.retrieve()方法的情况下允许DELETE?
  2.   

只需从视图类中删除 retrieve() 方法。也就是说,GenericViewSet不会提供任何 HTTP操作 ,除非它是在您的类中定义的。

因此,以下内容将是您的代码段,

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')

或者您可以在此处使用 mixin classes

from rest_framework.mixins import DestroyModelMixin


class ContentViewSet(DestroyModelMixin, GenericViewSet):

    def get_queryset(self):
        return Content.objects.filter(user=self.request.user)

  
      
  1. 为什么在未实施.retrieve()的情况下DRF无法创建urlconf?
  2.   

我不确定您如何定义网址。当我尝试使用 DRF路由器 时,它只是为定义的操作创建URL conf。

由于您已定义 GET,因此在端点上已执行 DELETE retrieve() 方法。

希望有帮助:)

答案 1 :(得分:0)

我对第1部分的解决方案是包括mixin但限制http_method_names

class ContentViewSet(RetrieveModelMixin, GenericViewSet):
    http_method_names = ['delete']
    ...

但是,我仍然完全不知道为什么必须包含RetrieveModelMixin

答案 2 :(得分:0)

在这里很容易猜到,但是您使用SimpleRouter还是DefaultRouter来构建urlpatterns吗?

如果是这样,那就是您的问题。路由器使用视图集,并期望实现所有方法。更多信息here

您所能做的就是将url添加到urlpatterns,就像通常使用.as_view()方法在django上所做的那样。