diff --git a/django/urls/resolvers.py b/django/urls/resolvers.py index 178d2737d2..eba1536580 100644 --- a/django/urls/resolvers.py +++ b/django/urls/resolvers.py @@ -164,6 +164,7 @@ class RegexURLResolver(LocaleRegexProvider): # urlpatterns self._callback_strs = set() self._populated = False + self._populating = False def __repr__(self): if isinstance(self.urlconf_name, list) and len(self.urlconf_name): @@ -177,6 +178,9 @@ class RegexURLResolver(LocaleRegexProvider): ) def _populate(self): + if self._populating: + return + self._populating = True lookups = MultiValueDict() namespaces = {} apps = {} @@ -209,7 +213,9 @@ class RegexURLResolver(LocaleRegexProvider): namespaces[namespace] = (p_pattern + prefix, sub_pattern) for app_name, namespace_list in pattern.app_dict.items(): apps.setdefault(app_name, []).extend(namespace_list) - self._callback_strs.update(pattern._callback_strs) + if not pattern._populating: + pattern._populate() + self._callback_strs.update(pattern._callback_strs) else: bits = normalize(p_pattern) lookups.appendlist(pattern.callback, (bits, p_pattern, pattern.default_args)) @@ -219,6 +225,7 @@ class RegexURLResolver(LocaleRegexProvider): self._namespace_dict[language_code] = namespaces self._app_dict[language_code] = apps self._populated = True + self._populating = False @property def reverse_dict(self): diff --git a/tests/admin_docs/namespace_urls.py b/tests/admin_docs/namespace_urls.py new file mode 100644 index 0000000000..d05922c33e --- /dev/null +++ b/tests/admin_docs/namespace_urls.py @@ -0,0 +1,14 @@ +from django.conf.urls import include, url +from django.contrib import admin + +from . import views + +backend_urls = ([ + url(r'^something/$', views.XViewClass.as_view(), name='something'), +], 'backend') + +urlpatterns = [ + url(r'^admin/doc/', include('django.contrib.admindocs.urls')), + url(r'^admin/', admin.site.urls), + url(r'^api/backend/', include(backend_urls, namespace='backend')), +] diff --git a/tests/admin_docs/tests.py b/tests/admin_docs/tests.py index 3d5955d680..82384a4bb8 100644 --- a/tests/admin_docs/tests.py +++ b/tests/admin_docs/tests.py @@ -88,6 +88,12 @@ class AdminDocViewTests(TestDataMixin, AdminDocsTestCase): # View docstring self.assertContains(response, 'Base view for admindocs views.') + @override_settings(ROOT_URLCONF='admin_docs.namespace_urls') + def test_namespaced_view_detail(self): + url = reverse('django-admindocs-views-detail', args=['admin_docs.views.XViewClass']) + response = self.client.get(url) + self.assertContains(response, '