1

I configured my api url as

localhost:port/app_name/students/{student_id}/macro/{macro_id}/lto

using drf-nested-routers extension. Basically, each students has some macro categories assigned, that in turns have some Long Term Objectives (LTOs). I've tested it using curl and Postman and everything seems to work. Now I need to write a more precise test case for my LTO model. This is my 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)),
]

The issue is that I cannot use the reverse() method correctly to get the url of my LTOViewSet to test it.

self.url = reverse('app_name:student-detail:lto', {getattr(self.student, 'id'), getattr(self.macro, 'id')})

This gives the following error

django.urls.exceptions.NoReverseMatch: 'student-detail' is not a registered namespace inside 'app_name'

In other test cases, I use very similar sentences and those work fine

self.list_url = reverse('app_name:student-list')

reverse('app_name:student-detail', {post_response.data['id']})
8
  • Side Note: You don't have to create routers.DefaultRouter objects more than once Commented Jul 25, 2020 at 16:56
  • @ArakkalAbu Even if I don't want to have student_router'urls nested with those ones of router? Commented Jul 25, 2020 at 17:02
  • So does knowing what URL namespaces are, help you? You're trying to reference lto by namespace, which you haven't created. Commented Jul 25, 2020 at 17:03
  • @Melvyn from what I've understood, for each namespace corresponds a app_name. I have everything inside a single app, so I shouldn't use other namespaces Commented Jul 25, 2020 at 17:07
  • The error message and reverse call don't match up: reverse('app_name:student-detail:lto' versus Reverse for 'student-detail-lto'. See colon versus -. So which of the two is it? Commented Jul 25, 2020 at 17:10

1 Answer 1

2

So here's the minimally reproducible example:

# 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/'

So indeed your error was passing just the router basename not a final endpoint to reverse and because of the nesting we were thrown off by student-detail not reversing (which I still don't get).

Sign up to request clarification or add additional context in comments.

3 Comments

student-detail does not need to get reversed manually. Once Django knows the final endpoint ('lto-detail/list' in this case), he automatically reverse the entire nested url. The only things he requires are the arguments in the url --> the primary key of student and of a macro in this case
Ah, I see now...when you updated the error message it complained about the namespace, not the url name anymore. All makes sense now!
Do you know whether I can use this approach to test nested urls?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.