diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py
index 14fc2822815cc8d6675f6b43bbdf091fd60b7393..2bbe0efe49a2ad9f030517eb3024d1c4e85379eb 100644
|
a
|
b
|
a string) and returns a tuple in this format:
|
| 8 | 8 | """ |
| 9 | 9 | from __future__ import unicode_literals |
| 10 | 10 | |
| | 11 | from collections import namedtuple |
| 11 | 12 | from importlib import import_module |
| 12 | 13 | import re |
| 13 | 14 | from threading import local |
| … |
… |
_prefixes = local()
|
| 36 | 37 | # Overridden URLconfs for each thread are stored here. |
| 37 | 38 | _urlconfs = local() |
| 38 | 39 | |
| | 40 | URLEntry = namedtuple('URLEntry', ['urlbits', 'p_pattern', 'default_args']) |
| | 41 | URLBit = namedtuple('URLBit', ['format', 'argument_names']) |
| | 42 | |
| 39 | 43 | |
| 40 | 44 | class ResolverMatch(object): |
| 41 | 45 | def __init__(self, func, args, kwargs, url_name=None, app_name=None, namespaces=None): |
| … |
… |
class RegexURLResolver(LocaleRegexProvider):
|
| 269 | 273 | if pattern.app_name: |
| 270 | 274 | apps.setdefault(pattern.app_name, []).append(pattern.namespace) |
| 271 | 275 | else: |
| 272 | | parent = normalize(pattern.regex.pattern) |
| | 276 | parent = [URLBit(*p) for p in normalize(pattern.regex.pattern)] |
| 273 | 277 | for name in pattern.reverse_dict: |
| 274 | 278 | for matches, pat, defaults in pattern.reverse_dict.getlist(name): |
| 275 | 279 | new_matches = [] |
| 276 | 280 | for piece, p_args in parent: |
| 277 | | new_matches.extend((piece + suffix, p_args + args) for (suffix, args) in matches) |
| 278 | | lookups.appendlist(name, (new_matches, p_pattern + pat, dict(defaults, **pattern.default_kwargs))) |
| | 281 | new_matches.extend([URLBit(piece + suffix, p_args + args) for (suffix, args) in matches]) |
| | 282 | lookups.appendlist(name, URLEntry(new_matches, p_pattern + pat, dict(defaults, **pattern.default_kwargs))) |
| 279 | 283 | for namespace, (prefix, sub_pattern) in pattern.namespace_dict.items(): |
| 280 | 284 | namespaces[namespace] = (p_pattern + prefix, sub_pattern) |
| 281 | 285 | for app_name, namespace_list in pattern.app_dict.items(): |
| 282 | 286 | apps.setdefault(app_name, []).extend(namespace_list) |
| 283 | 287 | else: |
| 284 | | bits = normalize(p_pattern) |
| 285 | | lookups.appendlist(pattern.callback, (bits, p_pattern, pattern.default_args)) |
| | 288 | bits = [URLBit(*p) for p in normalize(p_pattern)] |
| | 289 | lookups.appendlist(pattern.callback, URLEntry(bits, p_pattern, pattern.default_args)) |
| 286 | 290 | if pattern.name is not None: |
| 287 | | lookups.appendlist(pattern.name, (bits, p_pattern, pattern.default_args)) |
| | 291 | lookups.appendlist(pattern.name, URLEntry(bits, p_pattern, pattern.default_args)) |
| 288 | 292 | self._reverse_dict[language_code] = lookups |
| 289 | 293 | self._namespace_dict[language_code] = namespaces |
| 290 | 294 | self._app_dict[language_code] = apps |
| … |
… |
def is_valid_path(path, urlconf=None):
|
| 575 | 579 | return True |
| 576 | 580 | except Resolver404: |
| 577 | 581 | return False |
| | 582 | |
| | 583 | def get_urlformat(urlname): |
| | 584 | """ |
| | 585 | Given a URL name, returns the URL as a string suitable for string.format. |
| | 586 | |
| | 587 | Example:: |
| | 588 | |
| | 589 | urlpatterns = patterns('', |
| | 590 | url(r'^extra/(?P<extra>\w+)/$', empty_view, name="named-url2"), |
| | 591 | ) |
| | 592 | |
| | 593 | >>> get_urlformat('named-url2') |
| | 594 | '/extra/%(extra)s/' |
| | 595 | """ |
| | 596 | urlconf = get_urlconf() |
| | 597 | resolver = get_resolver(urlconf) |
| | 598 | urlbit = resolver.reverse_dict[urlname].urlbits[0] |
| | 599 | return "%s%s" % (get_script_prefix(), urlbit.format) |
diff --git a/tests/urlpatterns_reverse/tests.py b/tests/urlpatterns_reverse/tests.py
index 4d77dc946d2f9f0c7fda043fc707235c786eb9f9..9c08356afa485e4c4e15008913ec0a9ee1c37648 100644
|
a
|
b
|
from django.conf import settings
|
| 9 | 9 | from django.contrib.auth.models import User |
| 10 | 10 | from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist |
| 11 | 11 | from django.core.urlresolvers import (reverse, reverse_lazy, resolve, get_callable, |
| 12 | | get_resolver, NoReverseMatch, Resolver404, ResolverMatch, RegexURLResolver, |
| 13 | | RegexURLPattern) |
| | 12 | get_resolver, get_urlformat, NoReverseMatch, Resolver404, ResolverMatch, |
| | 13 | RegexURLResolver, RegexURLPattern) |
| 14 | 14 | from django.http import HttpRequest, HttpResponseRedirect, HttpResponsePermanentRedirect |
| 15 | 15 | from django.shortcuts import redirect |
| 16 | 16 | from django.test import TestCase |
| … |
… |
class ViewLoadingTests(TestCase):
|
| 657 | 657 | self.assertRaises(AttributeError, get_callable, |
| 658 | 658 | 'urlpatterns_reverse.views_broken.i_am_broken') |
| 659 | 659 | |
| | 660 | |
| | 661 | class URLObjects(TestCase): |
| | 662 | urls = 'urlpatterns_reverse.named_urls' |
| | 663 | |
| | 664 | def test_URL_objects(self): |
| | 665 | format = get_urlformat('named-url2') |
| | 666 | self.assertEqual(format, '/extra/%(extra)s/') |