Code

Ticket #6934: support-for-more-flexible-url-regex-patterns.patch

File support-for-more-flexible-url-regex-patterns.patch, 2.6 KB (added by sebastian_noack, 6 years ago)
  • django/core/urlresolvers.py

     
    8484 
    8585    Raises NoReverseMatch if the args/kwargs aren't valid for the regex. 
    8686    """ 
    87     # TODO: Handle nested parenthesis in the following regex. 
    88     result = re.sub(r'\(([^)]+)\)', MatchChecker(args, kwargs), regex.pattern) 
    89     return result.replace('^', '').replace('$', '') 
     87    url = grouped = '' 
     88    level = 0 
     89    match_checker = MatchChecker(args, kwargs) 
    9090 
     91    for c in regex.pattern: 
     92        if c == '(': 
     93            level += 1 
     94            if level == 1: 
     95                continue 
     96        elif c == ')': 
     97            level -= 1 
     98            if level == 0: 
     99                url += match_checker(grouped) 
     100                grouped = '' 
     101                continue 
     102         
     103        if level == 0: 
     104            url += c 
     105        else: 
     106            grouped += c 
     107 
     108    return url.replace('^', '').replace('$', '') 
     109 
    91110class MatchChecker(object): 
    92111    "Class used in reverse RegexURLPattern lookup." 
    93112    def __init__(self, args, kwargs): 
    94113        self.args, self.kwargs = args, kwargs 
    95114        self.current_arg = 0 
    96115 
    97     def __call__(self, match_obj): 
    98         # match_obj.group(1) is the contents of the parenthesis. 
     116    def __call__(self, grouped): 
     117        # grouped is the contents of the outer parenthesis. 
    99118        # First we need to figure out whether it's a named or unnamed group. 
    100119        # 
    101         grouped = match_obj.group(1) 
    102120        m = re.search(r'^\?P<(\w+)>(.*?)$', grouped, re.UNICODE) 
    103121        if m: # If this was a named group... 
    104122            # m.group(1) is the name of the group 
     
    115133                    # The arg wasn't passed in. 
    116134                    raise NoReverseMatch('Not enough positional arguments passed in') 
    117135            test_regex = m.group(2) 
    118         else: # Otherwise, this was a positional (unnamed) group. 
     136        elif not re.match(r'^\?', grouped, re.UNICODE): # If this was a positional (unnamed) group. 
    119137            try: 
    120138                value = self.args[self.current_arg] 
    121139                self.current_arg += 1 
     
    123141                # The arg wasn't passed in. 
    124142                raise NoReverseMatch('Not enough positional arguments passed in') 
    125143            test_regex = grouped 
     144        else: # Otherwise, it was a not-matching, look-ahead, or -behind group. 
     145            return u'' 
    126146        # Note we're using re.match here on purpose because the start of 
    127147        # to string needs to match. 
    128148        if not re.match(test_regex + '$', force_unicode(value), re.UNICODE):