web/lib/django/core/urlresolvers.py
changeset 29 cc9b7e14412b
parent 0 0d40e90630ef
equal deleted inserted replaced
28:b758351d191f 29:cc9b7e14412b
     8 """
     8 """
     9 
     9 
    10 import re
    10 import re
    11 
    11 
    12 from django.http import Http404
    12 from django.http import Http404
       
    13 from django.conf import settings
    13 from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
    14 from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
    14 from django.utils.datastructures import MultiValueDict
    15 from django.utils.datastructures import MultiValueDict
    15 from django.utils.encoding import iri_to_uri, force_unicode, smart_str
    16 from django.utils.encoding import iri_to_uri, force_unicode, smart_str
    16 from django.utils.functional import memoize
    17 from django.utils.functional import memoize
    17 from django.utils.importlib import import_module
    18 from django.utils.importlib import import_module
    18 from django.utils.regex_helper import normalize
    19 from django.utils.regex_helper import normalize
    19 from django.utils.thread_support import currentThread
    20 from django.utils.thread_support import currentThread
    20 
    21 
    21 try:
       
    22     reversed
       
    23 except NameError:
       
    24     from django.utils.itercompat import reversed     # Python 2.3 fallback
       
    25     from sets import Set as set
       
    26 
       
    27 _resolver_cache = {} # Maps URLconf modules to RegexURLResolver instances.
    22 _resolver_cache = {} # Maps URLconf modules to RegexURLResolver instances.
    28 _callable_cache = {} # Maps view and url pattern names to their view functions.
    23 _callable_cache = {} # Maps view and url pattern names to their view functions.
    29 
    24 
    30 # SCRIPT_NAME prefixes for each thread are stored here. If there's no entry for
    25 # SCRIPT_NAME prefixes for each thread are stored here. If there's no entry for
    31 # the current thread (which is the only one we ever access), it is assumed to
    26 # the current thread (which is the only one we ever access), it is assumed to
    32 # be empty.
    27 # be empty.
    33 _prefixes = {}
    28 _prefixes = {}
       
    29 
       
    30 # Overridden URLconfs for each thread are stored here.
       
    31 _urlconfs = {}
    34 
    32 
    35 class Resolver404(Http404):
    33 class Resolver404(Http404):
    36     pass
    34     pass
    37 
    35 
    38 class NoReverseMatch(Exception):
    36 class NoReverseMatch(Exception):
   129             return self._callback
   127             return self._callback
   130         try:
   128         try:
   131             self._callback = get_callable(self._callback_str)
   129             self._callback = get_callable(self._callback_str)
   132         except ImportError, e:
   130         except ImportError, e:
   133             mod_name, _ = get_mod_func(self._callback_str)
   131             mod_name, _ = get_mod_func(self._callback_str)
   134             raise ViewDoesNotExist, "Could not import %s. Error was: %s" % (mod_name, str(e))
   132             raise ViewDoesNotExist("Could not import %s. Error was: %s" % (mod_name, str(e)))
   135         except AttributeError, e:
   133         except AttributeError, e:
   136             mod_name, func_name = get_mod_func(self._callback_str)
   134             mod_name, func_name = get_mod_func(self._callback_str)
   137             raise ViewDoesNotExist, "Tried %s in module %s. Error was: %s" % (func_name, mod_name, str(e))
   135             raise ViewDoesNotExist("Tried %s in module %s. Error was: %s" % (func_name, mod_name, str(e)))
   138         return self._callback
   136         return self._callback
   139     callback = property(_get_callback)
   137     callback = property(_get_callback)
   140 
   138 
   141 class RegexURLResolver(object):
   139 class RegexURLResolver(object):
   142     def __init__(self, regex, urlconf_name, default_kwargs=None, app_name=None, namespace=None):
   140     def __init__(self, regex, urlconf_name, default_kwargs=None, app_name=None, namespace=None):
   228                         sub_match_dict.update(self.default_kwargs)
   226                         sub_match_dict.update(self.default_kwargs)
   229                         for k, v in sub_match[2].iteritems():
   227                         for k, v in sub_match[2].iteritems():
   230                             sub_match_dict[smart_str(k)] = v
   228                             sub_match_dict[smart_str(k)] = v
   231                         return sub_match[0], sub_match[1], sub_match_dict
   229                         return sub_match[0], sub_match[1], sub_match_dict
   232                     tried.append(pattern.regex.pattern)
   230                     tried.append(pattern.regex.pattern)
   233             raise Resolver404, {'tried': tried, 'path': new_path}
   231             raise Resolver404({'tried': tried, 'path': new_path})
   234         raise Resolver404, {'path' : path}
   232         raise Resolver404({'path' : path})
   235 
   233 
   236     def _get_urlconf_module(self):
   234     def _get_urlconf_module(self):
   237         try:
   235         try:
   238             return self._urlconf_module
   236             return self._urlconf_module
   239         except AttributeError:
   237         except AttributeError:
   244     def _get_url_patterns(self):
   242     def _get_url_patterns(self):
   245         patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
   243         patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
   246         try:
   244         try:
   247             iter(patterns)
   245             iter(patterns)
   248         except TypeError:
   246         except TypeError:
   249             raise ImproperlyConfigured("The included urlconf %s doesn't have any "
   247             raise ImproperlyConfigured("The included urlconf %s doesn't have any patterns in it" % self.urlconf_name)
   250                 "patterns in it" % self.urlconf_name)
       
   251         return patterns
   248         return patterns
   252     url_patterns = property(_get_url_patterns)
   249     url_patterns = property(_get_url_patterns)
   253 
   250 
   254     def _resolve_special(self, view_type):
   251     def _resolve_special(self, view_type):
   255         callback = getattr(self.urlconf_module, 'handler%s' % view_type)
   252         callback = getattr(self.urlconf_module, 'handler%s' % view_type)
   256         mod_name, func_name = get_mod_func(callback)
   253         try:
   257         try:
   254             return get_callable(callback), {}
   258             return getattr(import_module(mod_name), func_name), {}
       
   259         except (ImportError, AttributeError), e:
   255         except (ImportError, AttributeError), e:
   260             raise ViewDoesNotExist, "Tried %s. Error was: %s" % (callback, str(e))
   256             raise ViewDoesNotExist("Tried %s. Error was: %s" % (callback, str(e)))
   261 
   257 
   262     def resolve404(self):
   258     def resolve404(self):
   263         return self._resolve_special('404')
   259         return self._resolve_special('404')
   264 
   260 
   265     def resolve500(self):
   261     def resolve500(self):
   298             lookup_view_s = lookup_view
   294             lookup_view_s = lookup_view
   299         raise NoReverseMatch("Reverse for '%s' with arguments '%s' and keyword "
   295         raise NoReverseMatch("Reverse for '%s' with arguments '%s' and keyword "
   300                 "arguments '%s' not found." % (lookup_view_s, args, kwargs))
   296                 "arguments '%s' not found." % (lookup_view_s, args, kwargs))
   301 
   297 
   302 def resolve(path, urlconf=None):
   298 def resolve(path, urlconf=None):
       
   299     if urlconf is None:
       
   300         urlconf = get_urlconf()
   303     return get_resolver(urlconf).resolve(path)
   301     return get_resolver(urlconf).resolve(path)
   304 
   302 
   305 def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, current_app=None):
   303 def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, current_app=None):
       
   304     if urlconf is None:
       
   305         urlconf = get_urlconf()
   306     resolver = get_resolver(urlconf)
   306     resolver = get_resolver(urlconf)
   307     args = args or []
   307     args = args or []
   308     kwargs = kwargs or {}
   308     kwargs = kwargs or {}
   309 
   309 
   310     if prefix is None:
   310     if prefix is None:
   369     wishes to construct their own URLs manually (although accessing the request
   369     wishes to construct their own URLs manually (although accessing the request
   370     instance is normally going to be a lot cleaner).
   370     instance is normally going to be a lot cleaner).
   371     """
   371     """
   372     return _prefixes.get(currentThread(), u'/')
   372     return _prefixes.get(currentThread(), u'/')
   373 
   373 
       
   374 def set_urlconf(urlconf_name):
       
   375     """
       
   376     Sets the URLconf for the current thread (overriding the default one in
       
   377     settings). Set to None to revert back to the default.
       
   378     """
       
   379     thread = currentThread()
       
   380     if urlconf_name:
       
   381         _urlconfs[thread] = urlconf_name
       
   382     else:
       
   383         # faster than wrapping in a try/except
       
   384         if thread in _urlconfs:
       
   385             del _urlconfs[thread]
       
   386 
       
   387 def get_urlconf(default=None):
       
   388     """
       
   389     Returns the root URLconf to use for the current thread if it has been
       
   390     changed from the default one.
       
   391     """
       
   392     thread = currentThread()
       
   393     if thread in _urlconfs:
       
   394         return _urlconfs[thread]
       
   395     return default