Ticket #4566: reverse-speedup.diff

File reverse-speedup.diff, 3.9 KB (added by smoo, 17 years ago)

patch with above changes

  • core/urlresolvers.py

     
    1111from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
    1212import re
    1313
     14def cacheable(func, cache):
     15    def wrapper(arg):
     16        if arg in cache:
     17            return cache[arg]
     18       
     19        result = func(arg)
     20        cache[arg] = result
     21        return result
     22    return wrapper
     23
     24resolver_cache = {}
     25
     26def get_resolver(urlconf):
     27    if urlconf is None:
     28        from django.conf import settings
     29        urlconf = settings.ROOT_URLCONF
     30    return RegexURLResolver(r'^/', urlconf)
     31get_resolver = cacheable(get_resolver, resolver_cache)
     32
    1433class Resolver404(Http404):
    1534    pass
    1635
     
    160179        self.urlconf_name = urlconf_name
    161180        self.callback = None
    162181        self.default_kwargs = default_kwargs or {}
     182        self.reverse_dict = {}
     183       
     184        for pattern in reversed(self.urlconf_module.urlpatterns):
     185            if isinstance(pattern, RegexURLResolver):
     186                for key, value in pattern.reverse_dict.iteritems():
     187                    self.reverse_dict[key] = (pattern,) + value
     188            else:
     189                self.reverse_dict[pattern.callback] = (pattern,)
     190                self.reverse_dict[pattern.name] = (pattern,)
    163191
    164192    def resolve(self, path):
    165193        tried = []
     
    209237        return self._resolve_special('500')
    210238
    211239    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
     240        lookup_view = make_callable(lookup_view)
     241        if lookup_view in self.reverse_dict:
     242            url_parts = (reverse_helper(part.regex, *args, **kwargs) for part in self.reverse_dict[lookup_view])
     243            return ''.join(url_parts)
    230244        raise NoReverseMatch
    231245
    232246    def reverse_helper(self, lookup_view, *args, **kwargs):
     
    234248        result = reverse_helper(self.regex, *args, **kwargs)
    235249        return result + sub_match
    236250
     251callable_cache = {}
     252def make_callable(lookup_view):
     253    if not callable(lookup_view):
     254        mod_name, func_name = get_mod_func(lookup_view)
     255        if func_name != '':
     256            try:
     257                lookup_view = getattr(__import__(mod_name, {}, {}, ['']), func_name)
     258            except (ImportError, AttributeError):
     259                if func_name != '':
     260                    raise NoReverseMatch
     261    return lookup_view
     262make_callable = cacheable(make_callable, callable_cache)
     263
    237264def 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)
     265    resolver = get_resolver(urlconf)
    242266    return resolver.resolve(path)
    243267
    244268def reverse(viewname, urlconf=None, args=None, kwargs=None):
    245269    args = args or []
    246270    kwargs = kwargs or {}
    247     if urlconf is None:
    248         from django.conf import settings
    249         urlconf = settings.ROOT_URLCONF
    250     resolver = RegexURLResolver(r'^/', urlconf)
     271    resolver = get_resolver(urlconf)
    251272    return '/' + resolver.reverse(viewname, *args, **kwargs)
Back to Top