Django Rest Framework: используйте DELETE в GenericAPIView без реализации Retrieve

Я использую 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.

Мои вопросы:

  1. Как я могу разрешить DELETE без реализации метода .retrieve() и
  2. Почему DRF не может создать urlconf без реализации .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.

вы пробовали: django-rest-framework.org/api-guide/generic-views/…?

Hugo Brilhante 31.05.2019 04:17
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
2 491
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Мое решение для части 1 состоит в том, чтобы включить миксин, но ограничить http_method_names:

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

Тем не менее, я до сих пор не знаю, почему я вообще должен включать RetrieveModelMixin.

  1. 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)

  1. Why can't DRF create the urlconf without .retrieve() implemented?

Я не уверен, как вы определили свои URL-адреса. Когда я пытался использовать ДРФ-маршрутизатор, он создавал только конфигурацию URL для определенных действий.

У вас есть действия GET и DELETE на вашей конечной точке, потому что вы определили метод retrieve() в своем классе представления.

Надеюсь, это поможет :)

Спасибо, но в своем вопросе я упомянул, что уже пытался удалить метод retrieve()... и в результате delete() больше не работал, потому что drf не смог найти обратный URL.

gatlanticus 31.05.2019 05:58

Вы уверены ?, потому что обратные URL не влияют на метод удаления DRF

JPG 31.05.2019 06:00

И я не вижу фрагмента кода, связанного с этой проблемой, в вашем коде, а также в исходном коде.

JPG 31.05.2019 06:01

Да, я уверен, что запрос DELETE на реверс ('content-detail') работает для меня только в том случае, если присутствует метод retrieve (), иначе я получаю NoReverseMatch, как показано в вопросе. Я просто проверил, включив, а затем удалив метод retrieve(). Также удалось использовать RetrieveModelMixin для того же эффекта. Поскольку мой код проходит тест, это в основном любопытство на данный момент.

gatlanticus 31.05.2019 07:47

Вы можете добавить полная трассировка ошибок в OP?

JPG 31.05.2019 07:55

Я добавил полную трассировку ошибки, вызванной удалением .retrieve(). Как уже упоминалось, эта ошибка исчезает, когда функция retrieve() каким-то образом реализована.

gatlanticus 31.05.2019 09:00

@ ZG101 ZG101 Можете ли вы добавить функцию test_DELETE_content(), которая находится в myproject/myapp/tests.py?

JPG 31.05.2019 09:44

Давайте продолжить обсуждение в чате.

gatlanticus 31.05.2019 10:08
Ответ принят как подходящий

Дикое предположение, но вы использовали SimpleRouter или DefaultRouter, чтобы построить свой urlpatterns?

Если да, то это ваша проблема. Маршрутизатор использует набор представлений и ожидает реализации всех методов. Дополнительная информация здесь

Что вы можете сделать, так это просто добавить свой url к urlpatterns, как вы обычно делаете в django, используя метод .as_view().

Я использовал DefaultRouter. проверю и посмотрю результат

gatlanticus 31.05.2019 11:29

Ваше решение является наиболее прямым, но причина, по которой я выбрал GenericViewSet, заключалась в том, чтобы включить автоматическую маршрутизацию, как обычные наборы представлений DRF, без реализации каких-либо действий по умолчанию (чтобы я мог выбирать).

gatlanticus 31.05.2019 11:39

Другие вопросы по теме