Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

184 lines (166 sloc) 8.489 kb
Bugfix for issue #15900:
This code is largely reproduced from
and is the work of Django's authors:
It is licensed under Django's BSD license, available here:
To use, simply import this code in your project's root URLconf file before
defining any URL patterns.
from django.core import urlresolvers
if not hasattr(urlresolvers.RegexURLResolver, "_reverse_with_prefix"):
import re
from django.conf import urls
from django.utils.datastructures import MultiValueDict
from django.utils.encoding import iri_to_uri, force_unicode
from django.utils.regex_helper import normalize
def _populate(self):
lookups = MultiValueDict()
namespaces = {}
apps = {}
for pattern in reversed(self.url_patterns):
p_pattern = pattern.regex.pattern
if p_pattern.startswith('^'):
p_pattern = p_pattern[1:]
if isinstance(pattern, urlresolvers.RegexURLResolver):
if pattern.namespace:
namespaces[pattern.namespace] = (p_pattern, pattern)
if pattern.app_name:
apps.setdefault(pattern.app_name, []) \
parent = normalize(pattern.regex.pattern)
for name in pattern.reverse_dict:
for matches, pat, defaults in \
new_matches = []
for piece, p_args in parent:
vals = [(piece + suffix, p_args + args) for \
(suffix, args) in matches]
lookup_list = (new_matches, p_pattern + pat,
lookups.appendlist(name, lookup_list)
for namespace, (prefix, sub_pattern) in \
namespace_vals = (p_pattern + prefix, sub_pattern)
namespaces[namespace] = namespace_vals
for app_name, namespace_list in pattern.app_dict.items():
apps.setdefault(app_name, []).extend(namespace_list)
bits = normalize(p_pattern)
lookup_list = (bits, p_pattern, pattern.default_args)
lookups.appendlist(pattern.callback, lookup_list)
if is not None:
lookup_list = (bits, p_pattern, pattern.default_args)
lookups.appendlist(, lookup_list)
self._reverse_dict = lookups
self._namespace_dict = namespaces
self._app_dict = apps
def resolver_reverse(self, lookup_view, *args, **kwargs):
return self._reverse_with_prefix(lookup_view, '', *args, **kwargs)
def _reverse_with_prefix(self, lookup_view, _prefix, *args, **kwargs):
if args and kwargs:
raise ValueError("Don't mix *args and **kwargs in call to "
lookup_view = urlresolvers.get_callable(lookup_view, True)
except (ImportError, AttributeError), e:
raise urlresolvers.NoReverseMatch("Error importing '%s': %s."
% (lookup_view, e))
possibilities = self.reverse_dict.getlist(lookup_view)
prefix_norm, prefix_args = normalize(_prefix)[0]
for possibility, pattern, defaults in possibilities:
for result, params in possibility:
if args:
if len(args) != len(params) + len(prefix_args):
unicode_args = [force_unicode(val) for val in args]
candidate = (prefix_norm + result) \
% dict(zip(prefix_args + params, unicode_args))
if set(kwargs.keys() + defaults.keys()) != \
set(params + defaults.keys() + prefix_args):
matches = True
for k, v in defaults.items():
if kwargs.get(k, v) != v:
matches = False
if not matches:
unicode_kwargs = dict([(k, force_unicode(v)) for \
(k, v) in kwargs.items()])
candidate = (prefix_norm + result) % unicode_kwargs
if'^%s%s' % (_prefix, pattern),
candidate, re.UNICODE):
return candidate
# lookup_view can be URL label, or dotted path, or callable, Any of
# these can be passed in at the top, but callables are not friendly in
# error messages.
m = getattr(lookup_view, '__module__', None)
n = getattr(lookup_view, '__name__', None)
if m is not None and n is not None:
lookup_view_s = "%s.%s" % (m, n)
lookup_view_s = lookup_view
raise urlresolvers.NoReverseMatch("Reverse for '%s' with "
"arguments '%s' and keyword "
"arguments '%s' not found."
% (lookup_view_s, args, kwargs))
def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None,
if urlconf is None:
urlconf = urlresolvers.get_urlconf()
resolver = urlresolvers.get_resolver(urlconf)
args = args or []
kwargs = kwargs or {}
if prefix is None:
prefix = urlresolvers.get_script_prefix()
if not isinstance(viewname, basestring):
view = viewname
parts = viewname.split(':')
view = parts[0]
path = parts[1:]
resolved_path = []
while path:
ns = path.pop()
# Lookup the name to see if it could be an app identifier
app_list = resolver.app_dict[ns]
# Yes! Path part matches an app in the current Resolver
if current_app and current_app in app_list:
# If we are reversing for a particular app,
# use that namespace
ns = current_app
elif ns not in app_list:
# The name isn't shared by one of the instances
# (i.e., the default) so just pick the first instance
# as the default.
ns = app_list[0]
except KeyError:
extra, resolver = resolver.namespace_dict[ns]
prefix = prefix + extra
except KeyError, key:
if resolved_path:
raise urlresolvers.NoReverseMatch("%s is not a "
"registered namespace inside %s'"
% (key, ':'.join(resolved_path)))
raise urlresolvers.NoReverseMatch("%s is not a "
"registered "
"namespace" % key)
return iri_to_uri(resolver._reverse_with_prefix(view, prefix,
*args, **kwargs))
urlresolvers.RegexURLResolver._populate = _populate
urlresolvers.RegexURLResolver.reverse = resolver_reverse
urlresolvers.RegexURLResolver._reverse_with_prefix = _reverse_with_prefix
urlresolvers.reverse = reverse
Jump to Line
Something went wrong with that request. Please try again.