URL-адрес Django Rest Framework для настраиваемого действия не работает

На мой взгляд, у меня есть следующее настраиваемое действие:

class OrderAPIViewSet(viewsets.ViewSet):

    def create(self, request):
        print("Here: working")

    @action(detail=True, methods=['post'])
    def add(self, request, *arg, **kwargs):
        print("HERE in custom action")
        order = self.get_object()
        print(order)

urls.py моего приложения:

from rest_framework import routers
from .views import OrderAPIViewSet


router = routers.DefaultRouter()
router.register(r'orders', OrderAPIViewSet, basename='order')

urlpatterns = router.urls

Итак, в моем тесте, когда я пытаюсь получить доступ к orders/post, он работает, но когда я пытаюсь получить доступ к orders/{pk}/add, он терпит неудачу. Я имею в виду, что обратное само по себе не работает:

ORDERS_LIST_URL = reverse('order-list')
ORDERS_ADD_URL = reverse('order-add')

class PublicOrderApiTests(TestCase):

   def test_sample_test(self):
       data = {}
       res = self.client.post(ORDERS_ADD_URL, data, format='json')

как я уже сказал, у меня есть отдельный тест, в котором я использую ORDERS_LIST_URL вот так:

res = self.client.post(ORDERS_LIST_URL, data, format='json')

но при запуске теста я получаю следующую ошибку:

ImportError: не удалось импортировать тестовый модуль: orders.tests Traceback (последний вызов последним): файл /usr/local/lib/python3.7/unittest/loader.py, строка 436, в _find_test_path module = self._get_module_from_name (name) Файл /usr/local/lib/python3.7/unittest/loader.py, строка 377, в _get_module_from_name import (name) Файл /app/orders/tests.py, строка 22, в ORDERS_ADD_URL = reverse ('order-add') Файл /usr/local/lib/python3.7/site-packages/django/urls/base.py, строка 87, обратный возврат iri_to_uri (resolver._reverse_with_prefix (view, prefix, * args , ** kwargs)) Файл /usr/local/lib/python3.7/site-packages/django/urls/resolvers.py, строка 685, в _reverse_with_prefix поднять NoReverseMatch (msg) django.urls.exceptions.NoReverseMatch: Обратное для 'order-add' без аргументов не найден. 2 шаблона (ов) пробовали: ['orders / (? P [^ /.] +) / Add \. (? P [a-z0-9] +) /? $', 'Orders / (? P [^ /.************************************************************]

-------------------------------------------------- -------------------- Выполнить 1 тест за 0,000 с.

НЕ ВЫПОЛНЕНО (ошибки = 1)

согласно документации мне не нужно регистрировать эту конечную точку, маршрутизатор должен делать это сам. Что мне не хватает?


person Sebas Bond    schedule 02.03.2021    source источник
comment
удалите использование reverse(...) на уровне модуля и перенесите его на уровень вашего класса   -  person JPG    schedule 02.03.2021


Ответы (1)


Первое, что вы упустили, это pk наоборот. Поскольку для добавления API требуется pk вашего объекта Order, вам необходимо передать его обратной функции. Например:

order_add_url = reverse('order-add', kwargs={'pk': 1})
print(order_add_url)  # which will print '/orders/1/add/'

Поэтому я думаю, вам следует переместить эту часть в тело методов PublicOrderApiTests, поскольку вам нужен динамический URL-адрес для каждого тестового объекта.

Другая проблема заключается в том, что класс ViewSet не поддерживает self.get_object(), и если вы хотите использовать этот метод, вы должны либо иметь свой собственный метод, либо использовать остальную структуру GenericViewSet (т.е. from rest_framework.viewsets import GenericViewSet и наследовать от этого класса вместо ViewSet), тогда вы можете получить доступ к методу get_object() . Вы также можете узнать больше об общих представлениях в документации по остальной платформе.

person Roham    schedule 02.03.2021
comment
да, вот и все, спасибо. Я переместил константы URL в PublicOrderApiTests. Есть ли способ динамически заполнять идентификатор или каждый раз, когда я хочу вызвать эту конечную точку, мне нужно делать order_add_url = reverse('order-add', kwargs={'pk': 1}) в методе, выполняющем вызов? если да, то нет необходимости в определенной константе ORDERS_ADD_URL, верно? - person Sebas Bond; 02.03.2021
comment
Да, вы правы ... простой способ сделать это (цель динамического тестирования) - сначала создать объект Order в вашем методе (т.е. order_instance = Order.objects.create(required_fields_here), а затем использовать реверс сразу после создания объекта. Например order_add_url = reverse('order-add', kwargs={'pk': order_instance.id}). - person Roham; 03.03.2021
comment
И последний вопрос. Я думал, что этот метод можно использовать в качестве шаблона для создания других URL-адресов, но это не так. Я хотел создать конечную точку удаления, что-то вроде /order/{order_id}/remove/{item_id}, поэтому я создал @action для удаления и в моем тесте определил url=reverse('order-remove' kwargs={'pk':1,'order_id:'1'}, но это вызывает ошибку: django.urls.exceptions.NoReverseMatch: Reverse for 'order-remove' with keyword arguments '{'pk': 12345, 'product_id': 1}' not found. есть идеи, почему? - person Sebas Bond; 06.03.2021