Django

Code

Changeset 5516

Show
Ignore:
Timestamp:
06/23/07 00:40:28 (1 year ago)
Author:
mtredinnick
Message:

Fixed #4566 -- Added caching speed-ups to reverse URL matching. Based on a
patch from smoo.master@gmail.com.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/core/urlresolvers.py

    r5086 r5516  
    1010from django.http import Http404 
    1111from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist 
     12from django.utils.functional import memoize 
    1213import re 
     14 
     15_resolver_cache = {} # Maps urlconf modules to RegexURLResolver instances. 
     16_callable_cache = {} # Maps view and url pattern names to their view functions. 
    1317 
    1418class Resolver404(Http404): 
     
    1822    # Don't make this raise an error when used in a template. 
    1923    silent_variable_failure = True 
     24 
     25def get_callable(lookup_view): 
     26    if not callable(lookup_view): 
     27        mod_name, func_name = get_mod_func(lookup_view) 
     28        if func_name != '': 
     29            lookup_view = getattr(__import__(mod_name, {}, {}, ['']), func_name) 
     30    return lookup_view 
     31get_callable = memoize(get_callable, _callable_cache) 
     32 
     33def get_resolver(urlconf): 
     34    if urlconf is None: 
     35        from django.conf import settings 
     36        urlconf = settings.ROOT_URLCONF 
     37    return RegexURLResolver(r'^/', urlconf) 
     38get_resolver = memoize(get_resolver, _resolver_cache) 
    2039 
    2140def get_mod_func(callback): 
     
    130149        if self._callback is not None: 
    131150            return self._callback 
    132         mod_name, func_name = get_mod_func(self._callback_str) 
    133         try: 
    134             self._callback = getattr(__import__(mod_name, {}, {}, ['']), func_name) 
     151        try: 
     152            self._callback = get_callable(self._callback_str) 
    135153        except ImportError, e: 
    136154            raise ViewDoesNotExist, "Could not import %s. Error was: %s" % (mod_name, str(e)) 
     
    161179        self.callback = None 
    162180        self.default_kwargs = default_kwargs or {} 
     181        self.reverse_dict = {} 
     182 
     183        for pattern in reversed(self.urlconf_module.urlpatterns): 
     184            if isinstance(pattern, RegexURLResolver): 
     185                for key, value in pattern.reverse_dict.iteritems(): 
     186                    self.reverse_dict[key] = (pattern,) + value 
     187            else: 
     188                self.reverse_dict[pattern.callback] = (pattern,) 
     189                self.reverse_dict[pattern.name] = (pattern,) 
    163190 
    164191    def resolve(self, path): 
     
    210237 
    211238    def reverse(self, lookup_view, *args, **kwargs): 
    212         if not callable(lookup_view): 
    213             mod_name, func_name = get_mod_func(lookup_view) 
    214             try: 
    215                 lookup_view = getattr(__import__(mod_name, {}, {}, ['']), func_name) 
    216             except (ImportError, AttributeError): 
    217                 if func_name != '': 
    218                     raise NoReverseMatch 
    219         for pattern in self.urlconf_module.urlpatterns: 
    220             if isinstance(pattern, RegexURLResolver): 
    221                 try: 
    222                     return pattern.reverse_helper(lookup_view, *args, **kwargs) 
    223                 except NoReverseMatch: 
    224                     continue 
    225             elif pattern.callback == lookup_view or pattern.name == lookup_view: 
    226                 try: 
    227                     return pattern.reverse_helper(*args, **kwargs) 
    228                 except NoReverseMatch: 
    229                     continue 
     239        try: 
     240            lookup_view = get_callable(lookup_view) 
     241        except (ImportError, AttributeError): 
     242            raise NoReverseMatch 
     243        if lookup_view in self.reverse_dict: 
     244            return ''.join([reverse_helper(part.regex, *args, **kwargs) for part in self.reverse_dict[lookup_view]]) 
    230245        raise NoReverseMatch 
    231246 
     
    236251 
    237252def resolve(path, urlconf=None): 
    238     if urlconf is None: 
    239         from django.conf import settings 
    240         urlconf = settings.ROOT_URLCONF 
    241     resolver = RegexURLResolver(r'^/', urlconf) 
    242     return resolver.resolve(path) 
     253    return get_resolver(urlconf).resolve(path) 
    243254 
    244255def reverse(viewname, urlconf=None, args=None, kwargs=None): 
    245256    args = args or [] 
    246257    kwargs = kwargs or {} 
    247     if urlconf is None: 
    248         from django.conf import settings 
    249         urlconf = settings.ROOT_URLCONF 
    250     resolver = RegexURLResolver(r'^/', urlconf) 
    251     return '/' + resolver.reverse(viewname, *args, **kwargs) 
     258    return '/' + get_resolver(urlconf).reverse(viewname, *args, **kwargs) 
     259 
  • django/trunk/django/utils/functional.py

    r5091 r5516  
    33        return _curried_func(*(args+moreargs), **dict(kwargs, **morekwargs)) 
    44    return _curried 
     5 
     6def memoize(func, cache): 
     7    """ 
     8    Wrap a function so that results for any argument tuple are stored in 
     9    'cache'. Note that the args to the function must be usable as dictionary 
     10    keys. 
     11    """ 
     12    def wrapper(*args): 
     13        if args in cache: 
     14            return cache[args] 
     15 
     16        result = func(*args) 
     17        cache[args] = result 
     18        return result 
     19    return wrapper 
    520 
    621class Promise: