Django - 使用 drf-nested-routers 反向嵌套 url
Posted
技术标签:
【中文标题】Django - 使用 drf-nested-routers 反向嵌套 url【英文标题】:Django - reverse nested url with drf-nested-routers 【发布时间】:2020-11-15 08:15:30 【问题描述】:我将我的 api url 配置为
localhost:port/app_name/students/student_id/macro/macro_id/lto
使用 drf-nested-routers 扩展。基本上,每个学生都分配了一些宏观类别,这些类别又具有一些长期目标 (LTO)。我已经使用 curl 和 Postman 对其进行了测试,一切似乎都正常。 现在我需要为我的 LTO 模型编写一个更精确的测试用例。 这是我的 urls.py
from django.urls import path, re_path
from django.conf.urls import include
from rest_framework import routers
from app_name.views.views import UserViewSet, StudentViewSet, MacroViewSet, LTOViewSet, MacroAssignmentViewSet
from rest_framework_nested import routers as nested_routers
# application namespace
app_name = 'app_name'
router = routers.DefaultRouter()
router.register(r'users', UserViewSet, basename='user')
router.register(r'macro', MacroViewSet, basename='macro')
router.register(r'macro-assignments', MacroAssignmentViewSet, basename='macro-assignment')
student_router = routers.DefaultRouter()
student_router.register(r'students', StudentViewSet, basename='student')
lto_router = nested_routers.NestedSimpleRouter(student_router, r'students', lookup='student')
lto_router.register(r'macro/(?P<macro_pk>.+)/lto', LTOViewSet, basename='lto')
urlpatterns = [
re_path('^', include(router.urls)),
re_path('^', include(student_router.urls)),
re_path('^', include(lto_router.urls)),
]
问题是我无法正确使用 reverse() 方法来获取我的 LTOViewSet 的 url 来测试它。
self.url = reverse('app_name:student-detail:lto', getattr(self.student, 'id'), getattr(self.macro, 'id'))
这会产生以下错误
django.urls.exceptions.NoReverseMatch: 'student-detail' is not a registered namespace inside 'app_name'
在其他测试用例中,我使用非常相似的句子并且效果很好
self.list_url = reverse('app_name:student-list')
reverse('app_name:student-detail', post_response.data['id'])
【问题讨论】:
旁注:您不必多次创建routers.DefaultRouter
对象
@ArakkalAbu 即使我不想让student_router
'urls 嵌套在router
中?
那么知道URL namespaces 是什么,对您有帮助吗?您正在尝试按您尚未创建的命名空间引用 lto。
@Melvyn 据我了解,每个 namespace 对应一个 app_name。我将所有东西都放在一个应用程序中,所以我不应该使用其他命名空间
错误消息和反向调用不匹配:reverse('app_name:student-detail:lto'
与 Reverse for 'student-detail-lto'
。参见冒号与 -。那么这两者中的哪一个呢?
【参考方案1】:
所以这里是最小可重复的例子:
# main/viewsets.py
from rest_framework.viewsets import ModelViewSet
from django.contrib.auth.models import User, Group
class StudentViewSet(ModelViewSet):
model = User
class LTOViewSet(ModelViewSet):
model = Group
# main/urls.py
from django.urls import re_path, include
from rest_framework import routers
from rest_framework_nested import routers as nested_routers
from .viewsets import StudentViewSet, LTOViewSet
# application namespace
app_name = "main"
student_router = routers.DefaultRouter()
student_router.register(r"students", StudentViewSet, basename="student")
lto_router = nested_routers.NestedSimpleRouter(
student_router, r"students", lookup="student"
)
lto_router.register(r"macro/(?P<macro_pk>.+)/lto", LTOViewSet, basename="lto")
urlpatterns = [
re_path("^", include(student_router.urls)),
re_path("^", include(lto_router.urls)),
]
reverse('main:lto-detail', args=(1,1,1))
Out[5]: '/api/students/1/macro/1/lto/1/'
所以确实你的错误只是传递了路由器基名而不是最终端点来反转,并且由于嵌套我们被学生详细信息不反转(我仍然不明白)抛出。
【讨论】:
student-detail
不需要手动反转。一旦 Django 知道最终端点(在本例中为“lto-detail/list”),他就会自动反转整个嵌套的 url。他唯一需要的是 url 中的参数 --> 在这种情况下是学生和宏的主键
啊,我现在明白了……当您更新错误消息时,它抱怨的是命名空间,而不是 url 名称了。现在一切都说得通了!以上是关于Django - 使用 drf-nested-routers 反向嵌套 url的主要内容,如果未能解决你的问题,请参考以下文章