【问题标题】:get router url name when testing in Django Rest Framework在 Django Rest Framework 中测试时获取路由器 url 名称
【发布时间】: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: []

如何解决?

谢谢!

【问题讨论】:

    标签: python django rest django-rest-framework


    【解决方案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 codedocs 中看到这一点。所以在你的情况下,实际的反向应该是这样的:

      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 文档并且他们使用相同的方法。赞赏答案。
      猜你喜欢
      • 2020-10-07
      • 2015-09-26
      • 2020-08-07
      • 1970-01-01
      • 1970-01-01
      • 2018-07-04
      • 1970-01-01
      • 1970-01-01
      • 2016-06-15
      相关资源
      最近更新 更多