{{{
from django.test import TestCase
from django.conf.urls import url, include
from django.shortcuts import reverse
def my_view(**kwargs):
pass
class UrlConf(object):
# those are url patterns and views that I can re-used multiple times
common_url_patterns = [
# this is a page like any others
url(r'^$', my_view, name='page'),
# here is a namespace to let's say group actions together
# I clearly set a namespace to make it more logical
url(r'^actions/', include([
url(r'^action/$', my_view, name='action')
], namespace='actions'))
]
urlpatterns = [
# this is a part of my app into a namespace, nothing special about
it
url(r'^root/', include([
# depending of what are my keyword arguments
# I will use one of these two followings possibilities
url(r'^without-context/', include(common_url_patterns),
kwargs={'additional_arg': -21}),
url(r'^with-context/(?P<var>[0-9]+)/',
include(common_url_patterns))
# you may ask why I'm not using nested optional argument
# this is because I explicitly defined kwargs arguments for my
view in one cases
# but not in the other, so I cannot solve it that way
], namespace='root'))
]
class TestUrlResolver(TestCase):
def _test_reverse_for(self, viewname, kwargs, expected):
self.assertEqual(reverse(viewname, kwargs=kwargs,
urlconf=UrlConf), expected)
def test_page_without_var(self):
self._test_reverse_for('root:page', None, '/root/without-
context/')
def test_page_with_var(self):
self._test_reverse_for('root:page', {'var': 42}, '/root/with-
context/42/')
def test_action_without_var(self):
self._test_reverse_for('root:actions:action', None, '/root
/without-context/actions/action/')
def test_action_with_var(self):
self._test_reverse_for('root:actions:action', {'var': 42}, '/root
/with-context/42/actions/action/')
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/27597>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
Comment (by Tim Graham):
Could you update your example so that it doesn't raise a deprecation
warning? I see this:
{{{
RemovedInDjango20Warning: Specifying a namespace in
django.conf.urls.include() without providing an app_name is deprecated.
Set the app_name attribute in the included module, or pass a 2-tuple
containing the list of patterns and app_name instead.
], namespace='root'))
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/27597#comment:1>
Old description:
> def my_view(**kwargs):
> pass
>
New description:
The UrlResolver doesn't check possibilities through multiple namespaces ;
It'll look out for the viewname in a namespace to test all possibilities.
But the resolver won't go backward to other namespaces to list additional
possibilities that might match. I've few difficulties to define that issue
so I join this test case to reproduce it.
{{{
from django.test import TestCase
from django.conf.urls import url, include
from django.shortcuts import reverse
def my_view(**kwargs):
pass
class UrlConf(object):
app_name = 'myapp'
# those are url patterns and views that I can re-used multiple times
common_url_patterns = [
# this is a page like any others
url(r'^$', my_view, name='page'),
# here is a namespace to let's say group actions together
# I clearly set a namespace to make it more logical
url(r'^actions/', include(([
url(r'^action/$', my_view, name='action')
], app_name), namespace='actions'))
]
urlpatterns = [
# this is a part of my app into a namespace, nothing special about
it
url(r'^root/', include(([
# depending of what are my keyword arguments
# I will use one of these two followings possibilities
url(r'^without-context/', include(common_url_patterns),
kwargs={'additional_arg': -21}),
url(r'^with-context/(?P<var>[0-9]+)/',
include(common_url_patterns)),
# you may ask why I'm not using nested optional argument
# this is because I explicitly defined kwargs arguments for my
view in one cases
# but not in the other, so I cannot solve it that way
], app_name)))
]
class TestUrlResolver(TestCase):
def _test_reverse_for(self, viewname, kwargs, expected):
uri = reverse(viewname, kwargs=kwargs, urlconf=UrlConf)
self.assertEqual(uri, expected)
def test_page_without_var(self):
self._test_reverse_for('myapp:page', None, '/root/without-
context/')
def test_page_with_var(self):
self._test_reverse_for('myapp:page', {'var': 42}, '/root/with-
context/42/')
def test_action_without_var(self):
self._test_reverse_for('myapp:actions:action', None, '/root
/without-context/actions/action/')
def test_action_with_var(self):
self._test_reverse_for('myapp:actions:action', {'var': 42}, '/root
/with-context/42/actions/action/')
}}}
--
--
Ticket URL: <https://code.djangoproject.com/ticket/27597#comment:2>
* cc: Marten Kenbeek (added)
Comment:
Marten, any input?
--
Ticket URL: <https://code.djangoproject.com/ticket/27597#comment:3>
Comment (by Marten Kenbeek):
According to the [https://docs.djangoproject.com/en/1.10/topics/http/urls
/#url-namespaces docs]:
> **instance namespace**
>
> This identifies a specific instance of an application. Instance
namespaces **should be unique** across your entire project.
I believe that's what's happening here. You have multiple includes with
the exact same instance namespace, while Django expects that there is only
one. So I don't think it's a bug in Django.
I'm not sure whether this is actually desirable behaviour, or what kind of
impact changing it would have on existing projects. If we keep it as is,
it may be a good idea to add a system check that checks if instance
namespaces are indeed unique across the project.
--
Ticket URL: <https://code.djangoproject.com/ticket/27597#comment:4>
* status: new => closed
* resolution: => invalid
Comment:
Ok, I guess we'll close this for now. If someone wants to offer an
argument for changing the behavior, please write to the
DevelopersMailingList. Thanks for investigating, Marten. I created #27612
for your idea about a system check for unique instance namespaces.
--
Ticket URL: <https://code.djangoproject.com/ticket/27597#comment:5>