在 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_namebasename 取代 三个小时找到答案。我只是意识到这是因为我正在查看 drf 文档并且他们使用相同的方法。赞赏答案。

以上是关于在 Django Rest Framework 中测试时获取路由器 url 名称的主要内容,如果未能解决你的问题,请参考以下文章

django使用rest_framework

Django Rest Framework

Django rest framework 身份和权限验证

Django Rest Framework:非模型服务

django-rest-framework - 在可浏览的 API 中自动生成表单?

在 django-rest-framework 中,是不是可以同时使用 oauth 和 session 身份验证?