Ticket #2615: url_resolve.diff

File url_resolve.diff, 5.7 KB (added by norjee@…, 18 years ago)

Patch for urlresolvers.py

  • core/urlresolvers.py

     
    1717class NoReverseMatch(Exception):
    1818    pass
    1919
     20class ReversedMatch:
     21    """
     22    url is te resulting url
     23    matched_args is a list with matched named args
     24    default_args a hash, with the associated default args
     25    """
     26    def __init__(self, url , matched_kwargs , default_args):
     27        self.url = url
     28        self.matched_kwargs = matched_kwargs
     29        self.default_args = default_args
     30           
     31    def __add__(self , other):
     32        new_default_args = self.default_args.copy()
     33        new_default_args.update(other.default_args)
     34        return ReversedMatch(self.url + other.url , self.matched_kwargs + other.matched_kwargs , new_default_args)
     35   
     36    def get_unmatched_kwargs(self, kwargs):
     37        return dict([(k, v) for k , v in kwargs.items() if not k in self.matched_kwargs])
     38   
     39    def get_default_args(self):
     40        return self.default_args
     41   
     42    def get_url(self):
     43        return '/' + self.url
     44
    2045def get_mod_func(callback):
    2146    # Converts 'django.views.news.stories.story_detail' to
    2247    # ['django.views.news.stories', 'story_detail']
    2348    dot = callback.rindex('.')
    2449    return callback[:dot], callback[dot+1:]
    2550
    26 def reverse_helper(regex, *args, **kwargs):
     51def reverse_helper(regex, args, kwargs, default_args = None):
    2752    """
    2853    Does a "reverse" lookup -- returns the URL for the given args/kwargs.
    2954    The args/kwargs are applied to the given compiled regular expression.
     
    3863
    3964    Raises NoReverseMatch if the args/kwargs aren't valid for the regex.
    4065    """
     66   
    4167    # TODO: Handle nested parenthesis in the following regex.
    42     result = re.sub(r'\(([^)]+)\)', MatchChecker(args, kwargs), regex.pattern)
    43     return result.replace('^', '').replace('$', '')
     68    match_checker = MatchChecker(args, kwargs)
     69    result = re.sub(r'\(([^)]+)\)', match_checker, regex.pattern)
     70   
     71    matched_kwargs = match_checker.matched_kwargs
     72    url = result.replace('^', '').replace('$', '')
     73    return ReversedMatch(url , matched_kwargs , default_args or {})
    4474
    4575class MatchChecker(object):
    4676    "Class used in reverse RegexURLPattern lookup."
    4777    def __init__(self, args, kwargs):
    4878        self.args, self.kwargs = args, kwargs
    4979        self.current_arg = 0
     80        self.matched_kwargs = []
    5081
    5182    def __call__(self, match_obj):
    5283        # match_obj.group(1) is the contents of the parenthesis.
     
    5990            # m.group(2) is the regex.
    6091            try:
    6192                value = self.kwargs[m.group(1)]
     93                self.matched_kwargs.append(m.group(1))
    6294            except KeyError:
    6395                # It was a named group, but the arg was passed in as a
    6496                # positional arg or not at all.
     
    96128            self._callback = None
    97129            self._callback_str = callback
    98130        self.default_args = default_args or {}
    99 
     131       
    100132    def resolve(self, path):
    101133        match = self.regex.search(path)
    102134        if match:
     
    109141            if not kwargs:
    110142                args = match.groups()
    111143            # In both cases, pass any extra_kwargs as **kwargs.
    112             kwargs.update(self.default_args)
    113 
     144            kwargs.update(self.default_args)           
    114145            return self.callback, args, kwargs
    115146
    116147    def _get_callback(self):
     
    134165            raise NoReverseMatch
    135166        if lookup_view != self.callback:
    136167            raise NoReverseMatch
    137         return self.reverse_helper(*args, **kwargs)
     168        return self.reverse_helper(args, kwargs)
    138169
    139     def reverse_helper(self, *args, **kwargs):
    140         return reverse_helper(self.regex, *args, **kwargs)
     170    def reverse_helper(self, args, kwargs , default_args = {}):
     171        # default_args from parrent need to be taken into account
     172        default_args.update(self.default_args)
     173        return reverse_helper(self.regex, args, kwargs, default_args)
    141174
    142175class RegexURLResolver(object):
    143176    def __init__(self, regex, urlconf_name, default_kwargs=None):
     
    147180        self.urlconf_name = urlconf_name
    148181        self.callback = None
    149182        self.default_kwargs = default_kwargs or {}
    150 
     183               
    151184    def resolve(self, path):
    152185        tried = []
    153186        match = self.regex.search(path)
     
    210243                    continue
    211244            elif pattern.callback == lookup_view:
    212245                try:
    213                     return pattern.reverse_helper(*args, **kwargs)
     246                    return pattern.reverse_helper(args, kwargs , self.default_kwargs)
    214247                except NoReverseMatch:
    215248                    continue
    216249        raise NoReverseMatch
    217250
    218251    def reverse_helper(self, lookup_view, *args, **kwargs):
    219252        sub_match = self.reverse(lookup_view, *args, **kwargs)
    220         result = reverse_helper(self.regex, *args, **kwargs)
     253        result = reverse_helper(self.regex, args, kwargs , sub_match.default_args)
    221254        return result + sub_match
    222255
    223256def resolve(path, urlconf=None):
     
    227260    resolver = RegexURLResolver(r'^/', urlconf)
    228261    return resolver.resolve(path)
    229262
    230 def reverse(viewname, urlconf=None, args=None, kwargs=None):
     263def reverse_match(viewname, urlconf=None, args=None, kwargs=None):
    231264    args = args or []
    232265    kwargs = kwargs or {}
    233266    if urlconf is None:
    234267        from django.conf import settings
    235268        urlconf = settings.ROOT_URLCONF
    236269    resolver = RegexURLResolver(r'^/', urlconf)
    237     return '/' + resolver.reverse(viewname, *args, **kwargs)
     270    return resolver.reverse(viewname, *args, **kwargs)
     271
     272def reverse(viewname, urlconf=None, args=None, kwargs=None):       
     273    return '/' + reverse_match(viewname, urlconf, args, kwargs).url
Back to Top