diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py
index b634b56..2ab0235 100644
a
|
b
|
def get_mod_func(callback):
|
134 | 134 | dot = callback.rindex('.') |
135 | 135 | except ValueError: |
136 | 136 | return callback, '' |
137 | | return callback[:dot], callback[dot+1:] |
| 137 | return callback[:dot], callback[dot + 1:] |
138 | 138 | |
139 | 139 | class LocaleRegexProvider(object): |
140 | 140 | """ |
… |
… |
class RegexURLPattern(LocaleRegexProvider):
|
204 | 204 | else: |
205 | 205 | args = match.groups() |
206 | 206 | # In both cases, pass any extra_kwargs as **kwargs. |
207 | | kwargs.update(self.default_args) |
| 207 | kw = self.default_args.copy() |
| 208 | kw.update(kwargs) |
208 | 209 | |
209 | | return ResolverMatch(self.callback, args, kwargs, self.name) |
| 210 | return ResolverMatch(self.callback, args, kw, self.name) |
210 | 211 | |
211 | 212 | @property |
212 | 213 | def callback(self): |
… |
… |
class RegexURLResolver(LocaleRegexProvider):
|
368 | 369 | if len(args) != len(params) + len(prefix_args): |
369 | 370 | continue |
370 | 371 | unicode_args = [force_unicode(val) for val in args] |
371 | | candidate = (prefix_norm + result) % dict(zip(prefix_args + params, unicode_args)) |
| 372 | candidate = (prefix_norm + result) % dict(zip(prefix_args + params, unicode_args)) |
372 | 373 | else: |
373 | 374 | if set(kwargs.keys() + defaults.keys()) != set(params + defaults.keys() + prefix_args): |
374 | 375 | continue |
375 | 376 | matches = True |
376 | 377 | for k, v in defaults.items(): |
| 378 | if k in params: |
| 379 | continue |
377 | 380 | if kwargs.get(k, v) != v: |
378 | 381 | matches = False |
379 | 382 | break |
diff --git a/docs/topics/http/urls.txt b/docs/topics/http/urls.txt
index f3e27ae..1a30955 100644
a
|
b
|
Example requests:
|
110 | 110 | |
111 | 111 | .. _Dive Into Python's explanation: http://diveintopython.net/regular_expressions/street_addresses.html#re.matching.2.3 |
112 | 112 | |
| 113 | .. _named_groups: |
| 114 | |
113 | 115 | Named groups |
114 | 116 | ============ |
115 | 117 | |
… |
… |
Once you have defined namespaced URLs, you can reverse them. For details on
|
559 | 561 | reversing namespaced urls, see the documentation on :ref:`reversing namespaced |
560 | 562 | URLs <topics-http-reversing-url-namespaces>`. |
561 | 563 | |
| 564 | .. _pattern_extra_options: |
| 565 | |
562 | 566 | Passing extra options to view functions |
563 | 567 | ======================================= |
564 | 568 | |
… |
… |
options to views.
|
587 | 591 | |
588 | 592 | It's possible to have a URL pattern which captures named keyword arguments, |
589 | 593 | and also passes arguments with the same names in its dictionary of extra |
590 | | arguments. When this happens, the arguments in the dictionary will be used |
| 594 | arguments. When this happens, the arguments captured in the URL will be used |
| 595 | instead of the arguments in the dictionary. |
| 596 | |
| 597 | .. versionadded:: 1.4 |
| 598 | Previously, in case of a conflict, the arguments in the dictionary were used |
591 | 599 | instead of the arguments captured in the URL. |
592 | 600 | |
| 601 | |
593 | 602 | Passing extra options to ``include()`` |
594 | 603 | -------------------------------------- |
595 | 604 | |
… |
… |
If the URL does not resolve, the function raises an
|
933 | 942 | .. attribute:: ResolverMatch.kwargs |
934 | 943 | |
935 | 944 | The keyword arguments that would be passed to the view |
936 | | function, as parsed from the URL. |
937 | | |
| 945 | function, as parsed from the URL or provided to |
| 946 | :func:`~django.core.urlresolvers.pattern`, the keywords |
| 947 | parsed from the URL taking precedence whenever there is |
| 948 | a conflict. See :ref:`pattern_extra_options` and |
| 949 | :ref:`named_groups`. |
| 950 | |
938 | 951 | .. attribute:: ResolverMatch.url_name |
939 | 952 | |
940 | 953 | The name of the URL pattern that matches the URL. |
diff --git a/tests/regressiontests/i18n/patterns/tests.py b/tests/regressiontests/i18n/patterns/tests.py
index 1cc4520..5a8e868 100644
a
|
b
|
import os
|
4 | 4 | import warnings |
5 | 5 | |
6 | 6 | from django.core.exceptions import ImproperlyConfigured |
7 | | from django.core.urlresolvers import reverse, clear_url_caches |
| 7 | from django.core.urlresolvers import reverse, resolve, clear_url_caches |
8 | 8 | from django.test import TestCase |
9 | 9 | from django.test.utils import override_settings |
10 | 10 | from django.template import Template, Context |
… |
… |
class URLTagTests(URLTestCaseBase):
|
306 | 306 | {% language 'pt-br' %}{% url 'no-prefix-translated-slug' slug='apo' %}{% endlanguage %}""") |
307 | 307 | self.assertEqual(tpl.render(Context({})).strip().split(), |
308 | 308 | [u'/vertaald/apo/', u'/traduzidos/apo/']) |
| 309 | |
| 310 | |
| 311 | class URLExampleTests(URLTestCaseBase): |
| 312 | def test_demo(self): |
| 313 | # User accesses an english url. |
| 314 | with translation.override('en'): |
| 315 | match = resolve('/translated/apo/') |
| 316 | # Now we want provide links to the same page in other languages |
| 317 | links = [] |
| 318 | langs = ['nl', 'pt-br'] |
| 319 | for lang in langs: |
| 320 | with translation.override(lang): |
| 321 | links.append(reverse(match.url_name, args=match.args, kwargs=match.match_kwargs)) |
| 322 | self.assertEqual(links, [u'/vertaald/apo/', u'/traduzidos/apo/']) |
| 323 | # Now we can offer the user links to the other pages |
| 324 | # print "View the page in: ", |
| 325 | # for lang, link in zip(langs, links): |
| 326 | # print "<a href='%s'>%s</a> % (link, lang), |
diff --git a/tests/regressiontests/i18n/patterns/urls/default.py b/tests/regressiontests/i18n/patterns/urls/default.py
index f117502..6b94cba 100644
a
|
b
|
view = TemplateView.as_view(template_name='dummy.html')
|
9 | 9 | urlpatterns = patterns('', |
10 | 10 | url(r'^not-prefixed/$', view, name='not-prefixed'), |
11 | 11 | url(_(r'^translated/$'), view, name='no-prefix-translated'), |
12 | | url(_(r'^translated/(?P<slug>[\w-]+)/$'), view, name='no-prefix-translated-slug'), |
| 12 | url(_(r'^translated/(?P<slug>[\w-]+)/$'), view, {'extra': True}, name='no-prefix-translated-slug'), |
13 | 13 | ) |
14 | 14 | |
15 | 15 | urlpatterns += i18n_patterns('', |
diff --git a/tests/regressiontests/urlpatterns_reverse/tests.py b/tests/regressiontests/urlpatterns_reverse/tests.py
index a1c9244..8683d60 100644
a
|
b
|
class ErroneousViewTests(TestCase):
|
511 | 511 | self.assertRaises(ViewDoesNotExist, self.client.get, '/missing_outer/') |
512 | 512 | self.assertRaises(ViewDoesNotExist, self.client.get, '/uncallable/') |
513 | 513 | |
| 514 | class TestRereverse(TestCase): |
| 515 | urls = 'regressiontests.urlpatterns_reverse.urls' |
| 516 | |
| 517 | def test_kwargs_conflict(self): |
| 518 | match = resolve('/rereverse-overridden/12/url/') |
| 519 | self.assertEqual(match.kwargs, {'arg': '12', 'extra': True, 'overridden': 'url'}) |
| 520 | |
| 521 | def test_rereverse(self): |
| 522 | match = resolve('/rereverse/12/') |
| 523 | self.assertEqual(reverse(match.url_name, args=match.args, kwargs=match.kwargs), '/rereverse/12/') |
| 524 | match = resolve('/rereverse-overridden/12/url/') |
| 525 | self.assertEqual(reverse(match.url_name, args=match.args, kwargs=match.kwargs), '/rereverse-overridden/12/url/') |
diff --git a/tests/regressiontests/urlpatterns_reverse/urls.py b/tests/regressiontests/urlpatterns_reverse/urls.py
index 1d4ae73..4a3ff6a 100644
a
|
b
|
urlpatterns = patterns('',
|
41 | 41 | url(r'^windows_path/(?P<drive_name>[A-Z]):\\(?P<path>.+)/$', empty_view, |
42 | 42 | name="windows"), |
43 | 43 | url(r'^special_chars/(.+)/$', empty_view, name="special"), |
| 44 | url(r'^rereverse/(?P<arg>\d+)/$', empty_view, {'extra': True}, name='rereverse'), |
| 45 | url(r'^rereverse-overridden/(?P<arg>\d+)/(?P<overridden>\w+)/$', empty_view, {'extra': True, 'overridden': 'default'}, name='rereverse-overridden'), |
44 | 46 | url(r'^(?P<name>.+)/\d+/$', empty_view, name="mixed"), |
45 | 47 | url(r'^repeats/a{1,2}/$', empty_view, name="repeats"), |
46 | 48 | url(r'^repeats/a{2,4}/$', empty_view, name="repeats2"), |