Я использую Django Rest Framework и хочу иметь возможность удалять экземпляр Content через DELETE
to /api/content/<int:pk>/
. Я не хочу реализовать любой метод для ответа на запросы 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: Reverse for 'content-detail' not found. 'content-detail' is not a valid view function or pattern name.
Я не проверял, но предполагаю, что то же самое произойдет с PUT
и PATCH
.
Мои вопросы:
DELETE
без реализации метода .retrieve()
и.retrieve()
?ОБНОВЛЕНИЕ: Неудачный тест и полная трассировка ошибок, вызванная удалением метода .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.
Мое решение для части 1 состоит в том, чтобы включить миксин, но ограничить http_method_names
:
class ContentViewSet(RetrieveModelMixin, GenericViewSet):
http_method_names = ['delete']
...
Тем не менее, я до сих пор не знаю, почему я вообще должен включать RetrieveModelMixin
.
- How can I allow DELETE without implementing a
.retrieve()
method?
Просто удалите метод 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)
- Why can't DRF create the urlconf without
.retrieve()
implemented?
Я не уверен, как вы определили свои URL-адреса. Когда я пытался использовать ДРФ-маршрутизатор, он создавал только конфигурацию URL для определенных действий.
У вас есть действия GET
и DELETE
на вашей конечной точке, потому что вы определили метод retrieve()
в своем классе представления.
Надеюсь, это поможет :)
Спасибо, но в своем вопросе я упомянул, что уже пытался удалить метод retrieve()... и в результате delete() больше не работал, потому что drf не смог найти обратный URL.
Вы уверены ?, потому что обратные URL не влияют на метод удаления DRF
И я не вижу фрагмента кода, связанного с этой проблемой, в вашем коде, а также в исходном коде.
Да, я уверен, что запрос DELETE на реверс ('content-detail') работает для меня только в том случае, если присутствует метод retrieve (), иначе я получаю NoReverseMatch
, как показано в вопросе. Я просто проверил, включив, а затем удалив метод retrieve(). Также удалось использовать RetrieveModelMixin для того же эффекта. Поскольку мой код проходит тест, это в основном любопытство на данный момент.
Вы можете добавить полная трассировка ошибок в OP?
Я добавил полную трассировку ошибки, вызванной удалением .retrieve()
. Как уже упоминалось, эта ошибка исчезает, когда функция retrieve() каким-то образом реализована.
@ ZG101 ZG101 Можете ли вы добавить функцию test_DELETE_content()
, которая находится в myproject/myapp/tests.py
?
Давайте продолжить обсуждение в чате.
Дикое предположение, но вы использовали SimpleRouter
или DefaultRouter
, чтобы построить свой urlpatterns
?
Если да, то это ваша проблема. Маршрутизатор использует набор представлений и ожидает реализации всех методов. Дополнительная информация здесь
Что вы можете сделать, так это просто добавить свой url
к urlpatterns
, как вы обычно делаете в django, используя метод .as_view()
.
Я использовал DefaultRouter
. проверю и посмотрю результат
Ваше решение является наиболее прямым, но причина, по которой я выбрал GenericViewSet, заключалась в том, чтобы включить автоматическую маршрутизацию, как обычные наборы представлений DRF, без реализации каких-либо действий по умолчанию (чтобы я мог выбирать).
вы пробовали: django-rest-framework.org/api-guide/generic-views/…?