在 Django Rest Framework 中测试时获取路由器 url 名称
Posted
技术标签:
【中文标题】在 Django Rest Framework 中测试时获取路由器 url 名称【英文标题】:get router url name when testing in Django Rest Framework 【发布时间】:2015-11-01 10:52:40 【问题描述】:我有一些问题。我在 Django Rest Framework 中使用路由器,我想测试一些 api 方法。
在 urls.py 中:
router = DefaultRouter()
router.register(r'my-list', MyViewSet, base_name="my_list")
urlpatterns = [
url(r'^api/', include(router.urls,
namespace='api'), ),
]
所以,在 tests.py 中,我想使用 reverse 之类的东西。现在我用
response = self.client.get('/api/my-list/')
如果我使用,它是一个硬编码字符串:
response = self.client.get(reverse('api:my_list')
我有一个错误:
django.core.urlresolvers.NoReverseMatch: Reverse for 'my_list' with arguments '()' and keyword arguments '' not found. 0 pattern(s) tried: []
如何解决?
谢谢!
【问题讨论】:
【参考方案1】:2021 年更新。
我已从@miki725 答案中添加了更多详细信息。
有些细节需要有一些考虑,比如app_name
参数需要放在myappname.urls
里面。
因此urls.py
应该如下所示:
# django imports
from django.urls import path, include
# drf imports
from rest_framework import routers
from myappname.viewsets import UserViewSet
# In the example used in the question the app_name is 'api'
app_name = 'myappname' # <---- Needed when testing API URLS..
router = routers.DefaultRouter()
router.register(r'users', UserViewSet, basename='user') # <---- Here already have -list and -detail by default.
urlpatterns = [
path('', include(router.urls)),
]
tests.py
from myappname.models import User
from django.urls import reverse
from django.utils import timezone
from rest_framework import status
from rest_framework.test import APITestCase
class TestApi(APITestCase):
def setUp(self):
self.headerInfo = 'content-type': 'application/json'
# example of query to be used on URL.
self.user = User.objects.create(
username = 'anyname',
created_at=timezone.now(),
created_by='testname',
)
self.user.save()
# payload to be used to test PUT method for example...
self.user_data =
'username': 'othername',
'created_at': timezone.now(),
'created_by': 'othertestname'
# again: In the example used in the question the app_name is 'api'
# that's why reverse('api:my-list')...
self.url_user_list = reverse('myappname:user-list')
self.url_user_detail = reverse('myappname:user-detail',
kwargs='pk': self.user.pk)
"""
Test User endpont.
"""
def test_get_user(self):
"""GET method"""
response = self.client.get(self.url_user_list,
self.user_data,
format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_create_user(self):
""" test POST method for User endpoint"""
response = self.client.post(
self.url_user_list, self.user_data,
# headers=self.headerInfo,
format='json'
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
def test_update_user(self):
data =
'username': 'someothername',
'created_at': timezone.now(),
'created_by': 'someothertestname'
response = self.client.put(self.url_user_detail, data, headers=self.headerInfo)
self.assertEqual(response.status_code, status.HTTP_200_OK)
【讨论】:
【参考方案2】:DRF 在视图集中为不同的 URL 添加后缀 - 列表、详细信息和可能的自定义 URL。您可以在source code 和docs 中看到这一点。所以在你的情况下,实际的反向应该是这样的:
reverse('api:my_list-list') # for list URL. e.g. /api/my-list/
reverse('api:my_list-detail') # for detail URL. e.g. /api/my-list/<pk>/
这就是为什么最好使用资源名称作为路由器base_name
。例如base_name='user'
与base_name='users_list'
。
【讨论】:
base_name
被 basename
取代
三个小时找到答案。我只是意识到这是因为我正在查看 drf 文档并且他们使用相同的方法。赞赏答案。以上是关于在 Django Rest Framework 中测试时获取路由器 url 名称的主要内容,如果未能解决你的问题,请参考以下文章