自定义操作的 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 不起作用的主要内容,如果未能解决你的问题,请参考以下文章
如何在 django rest 框架中反转 ViewSet 自定义操作的 URL
用于覆盖 post 方法的 Django REST 框架自定义装饰器
raise PermissionDenied 中的自定义消息在 Django rest 中不起作用