自定义操作的 Django Rest Framework URL 不起作用

Posted

技术标签:

【中文标题】自定义操作的 Django Rest Framework URL 不起作用【英文标题】:Django Rest Framework URL for custom action not working 【发布时间】:2021-05-31 14:56:39 【问题描述】:

我的视图中有以下自定义操作:

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 模块 = self._get_module_from_name(name) 文件“/usr/local/lib/python3.7/unittest/loader.py”,第 377 行,在 _get_module_from_name import(名称)文件“/app/orders/tests.py”,第 22 行,在 ORDERS_ADD_URL = reverse('order-add') 文件“/usr/local/lib/python3.7/site-packages/django/urls/base.py”,第 87 行, 相反 return 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 raise NoReverseMatch(msg) django.urls.exceptions.NoReverseMatch:“order-add”的反向,没有找不到参数。 2 个图案 试过:['orders/(?P[^/.]+)/add\.(?P[a-z0-9]+)/?$', '订单/(?P[^/.]+)/add/$']

----------------------------------- ----------------------- 在 0.000 秒内运行 1 次测试

失败(错误=1)

根据文档我不需要注册这个端点,路由器应该自己做。我错过了什么?

【问题讨论】:

在模块级别删除reverse(...)的使用并将其带到您的班级级别 【参考方案1】:

你错过的第一件事是pk 在你的反面。由于添加 API 需要您的 Order 对象的 pk,因此您需要将其传递给 reverse 函数。例如:

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(),如果你想使用这个方法你应该有自己的方法或者使用rest框架GenericViewSet(即from rest_framework.viewsets import GenericViewSet并从这个类继承而不是ViewSet) 那么您可以访问get_object() 方法。您还可以在rest framework docs 中阅读有关通用视图的更多信息。

【讨论】:

是的,就是这样,谢谢。我将 URL consts 移动到 PublicOrderApiTests。有没有办法动态填充 id 或者每次我想调用该端点时我需要在执行调用的方法中执行 order_add_url = reverse('order-add', kwargs='pk': 1) ?如果是这样,就不需要定义的 const ORDERS_ADD_URL 对吧? 是的,你是对的......一个简单的方法(动态测试目的)是首先在你的方法中创建一个Order对象(即order_instance = Order.objects.create(required_fields_here),然后使用反向只是创建对象后。例如order_add_url = reverse('order-add', kwargs='pk': order_instance.id) 最后一个问题。我认为这种方法可以用作模板来构造其他 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.知道为什么吗?

以上是关于自定义操作的 Django Rest Framework URL 不起作用的主要内容,如果未能解决你的问题,请参考以下文章