Fixed #27367 -- Doc'd and tested reversing of URLs with the same name.
Thanks Reinout van Rees for contributing to the patch.
This commit is contained in:
parent
fb5bd38e3b
commit
98bcc5d81b
|
@ -597,15 +597,28 @@ In order to perform URL reversing, you'll need to use **named URL patterns**
|
|||
as done in the examples above. The string used for the URL name can contain any
|
||||
characters you like. You are not restricted to valid Python names.
|
||||
|
||||
When you name your URL patterns, make sure you use names that are unlikely
|
||||
to clash with any other application's choice of names. If you call your URL
|
||||
pattern ``comment``, and another application does the same thing, there's
|
||||
no guarantee which URL will be inserted into your template when you use
|
||||
this name.
|
||||
When naming URL patterns, choose names that are unlikely to clash with other
|
||||
applications' choice of names. If you call your URL pattern ``comment``
|
||||
and another application does the same thing, the URL that
|
||||
:func:`~django.urls.reverse()` finds depends on whichever pattern is last in
|
||||
your project's ``urlpatterns`` list.
|
||||
|
||||
Putting a prefix on your URL names, perhaps derived from the application
|
||||
name, will decrease the chances of collision. We recommend something like
|
||||
``myapp-comment`` instead of ``comment``.
|
||||
name (such as ``myapp-comment`` instead of ``comment``), decreases the chance
|
||||
of collision.
|
||||
|
||||
You can deliberately choose the *same URL name* as another application if you
|
||||
want to override a view. For example, a common use case is to override the
|
||||
:class:`~django.contrib.auth.views.LoginView`. Parts of Django and most
|
||||
third-party apps assume that this view has a URL pattern with the name
|
||||
``login``. If you have a custom login view and give its URL the name ``login``,
|
||||
:func:`~django.urls.reverse()` will find your custom view as long as it's in
|
||||
``urlpatterns`` after ``django.contrib.auth.urls`` is included (if that's
|
||||
included at all).
|
||||
|
||||
You may also use the same name for multiple URL patterns if they differ in
|
||||
their arguments. In addition to the URL name, :func:`~django.urls.reverse()`
|
||||
matches the number of arguments and the names of the keyword arguments.
|
||||
|
||||
.. _topics-http-defining-url-namespaces:
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
from django.conf.urls import url
|
||||
|
||||
from .views import empty_view
|
||||
|
||||
urlpatterns = [
|
||||
# No kwargs
|
||||
url(r'^conflict/cannot-go-here/$', empty_view, name='name-conflict'),
|
||||
url(r'^conflict/$', empty_view, name='name-conflict'),
|
||||
# One kwarg
|
||||
url(r'^conflict-first/(?P<first>\w+)/$', empty_view, name='name-conflict'),
|
||||
url(r'^conflict-cannot-go-here/(?P<middle>\w+)/$', empty_view, name='name-conflict'),
|
||||
url(r'^conflict-middle/(?P<middle>\w+)/$', empty_view, name='name-conflict'),
|
||||
url(r'^conflict-last/(?P<last>\w+)/$', empty_view, name='name-conflict'),
|
||||
# Two kwargs
|
||||
url(r'^conflict/(?P<another>\w+)/(?P<extra>\w+)/cannot-go-here/$', empty_view, name='name-conflict'),
|
||||
url(r'^conflict/(?P<extra>\w+)/(?P<another>\w+)/$', empty_view, name='name-conflict'),
|
||||
]
|
|
@ -386,6 +386,23 @@ class ResolverTests(SimpleTestCase):
|
|||
self.assertEqual(resolver.reverse('named-url2', 'arg'), 'extra/arg/')
|
||||
self.assertEqual(resolver.reverse('named-url2', extra='arg'), 'extra/arg/')
|
||||
|
||||
def test_resolver_reverse_conflict(self):
|
||||
"""
|
||||
url() name arguments don't need to be unique. The last registered
|
||||
pattern takes precedence for conflicting names.
|
||||
"""
|
||||
resolver = get_resolver('urlpatterns_reverse.named_urls_conflict')
|
||||
# Without arguments, the last URL in urlpatterns has precedence.
|
||||
self.assertEqual(resolver.reverse('name-conflict'), 'conflict/')
|
||||
# With an arg, the last URL in urlpatterns has precedence.
|
||||
self.assertEqual(resolver.reverse('name-conflict', 'arg'), 'conflict-last/arg/')
|
||||
# With a kwarg, other url()s can be reversed.
|
||||
self.assertEqual(resolver.reverse('name-conflict', first='arg'), 'conflict-first/arg/')
|
||||
self.assertEqual(resolver.reverse('name-conflict', middle='arg'), 'conflict-middle/arg/')
|
||||
self.assertEqual(resolver.reverse('name-conflict', last='arg'), 'conflict-last/arg/')
|
||||
# The number and order of the arguments don't interfere with reversing.
|
||||
self.assertEqual(resolver.reverse('name-conflict', 'arg', 'arg'), 'conflict/arg/arg/')
|
||||
|
||||
def test_non_regex(self):
|
||||
"""
|
||||
A Resolver404 is raised if resolving doesn't meet the basic
|
||||
|
|
Loading…
Reference in New Issue