Loading django/core/urlresolvers.py +78 −0 Original line number Diff line number Diff line Loading @@ -14,12 +14,56 @@ import re class Resolver404(Http404): pass class NoReverseMatch(Exception): pass def get_mod_func(callback): # Converts 'django.views.news.stories.story_detail' to # ['django.views.news.stories', 'story_detail'] dot = callback.rindex('.') return callback[:dot], callback[dot+1:] class MatchChecker(object): "Class used in reverse RegexURLPattern lookup." def __init__(self, args, kwargs): self.args, self.kwargs = args, kwargs self.current_arg = 0 def __call__(self, match_obj): # match_obj.group(1) is the contents of the parenthesis. # First we need to figure out whether it's a named or unnamed group. # grouped = match_obj.group(1) m = re.search(r'^\?P<(\w+)>(.*?)$', grouped) if m: # If this was a named group... # m.group(1) is the name of the group # m.group(2) is the regex. try: value = self.kwargs[m.group(1)] except KeyError: # It was a named group, but the arg was passed in as a # positional arg or not at all. try: value = self.args[self.current_arg] self.current_arg += 1 except IndexError: # The arg wasn't passed in. raise NoReverseMatch('Not enough positional arguments passed in') test_regex = m.group(2) else: # Otherwise, this was a positional (unnamed) group. try: value = self.args[self.current_arg] self.current_arg += 1 except IndexError: # The arg wasn't passed in. raise NoReverseMatch('Not enough positional arguments passed in') test_regex = grouped # Note we're using re.match here on purpose because the start of # to string needs to match. if not re.match(test_regex + '$', str(value)): # TODO: Unicode? raise NoReverseMatch("Value %r didn't match regular expression %r" % (value, test_regex)) return str(value) # TODO: Unicode? class RegexURLPattern: def __init__(self, regex, callback, default_args=None): # regex is a string representing a regular expression. Loading Loading @@ -58,12 +102,37 @@ class RegexURLPattern: except AttributeError, e: raise ViewDoesNotExist, "Tried %s in module %s. Error was: %s" % (func_name, mod_name, str(e)) def reverse(self, viewname, *args, **kwargs): if viewname != self.callback: raise NoReverseMatch return self.reverse_helper(*args, **kwargs) def reverse_helper(self, *args, **kwargs): """ Does a "reverse" lookup -- returns the URL for the given args/kwargs. The args/kwargs are applied to the regular expression in this RegexURLPattern. For example: >>> RegexURLPattern('^places/(\d+)/$').reverse_helper(3) 'places/3/' >>> RegexURLPattern('^places/(?P<id>\d+)/$').reverse_helper(id=3) 'places/3/' >>> RegexURLPattern('^people/(?P<state>\w\w)/(\w+)/$').reverse_helper('adrian', state='il') 'people/il/adrian/' Raises NoReverseMatch if the args/kwargs aren't valid for the RegexURLPattern. """ # TODO: Handle nested parenthesis in the following regex. result = re.sub(r'\(([^)]+)\)', MatchChecker(args, kwargs), self.regex.pattern) return result.replace('^', '').replace('$', '') class RegexURLResolver(object): def __init__(self, regex, urlconf_name): # regex is a string representing a regular expression. # urlconf_name is a string representing the module containing urlconfs. self.regex = re.compile(regex) self.urlconf_name = urlconf_name self.callback = None def resolve(self, path): tried = [] Loading Loading @@ -110,3 +179,12 @@ class RegexURLResolver(object): def resolve500(self): return self._resolve_special('500') def reverse(self, viewname, *args, **kwargs): for pattern in self.urlconf_module.urlpatterns: if pattern.callback == viewname: try: return pattern.reverse_helper(*args, **kwargs) except NoReverseMatch: continue raise NoReverseMatch Loading
django/core/urlresolvers.py +78 −0 Original line number Diff line number Diff line Loading @@ -14,12 +14,56 @@ import re class Resolver404(Http404): pass class NoReverseMatch(Exception): pass def get_mod_func(callback): # Converts 'django.views.news.stories.story_detail' to # ['django.views.news.stories', 'story_detail'] dot = callback.rindex('.') return callback[:dot], callback[dot+1:] class MatchChecker(object): "Class used in reverse RegexURLPattern lookup." def __init__(self, args, kwargs): self.args, self.kwargs = args, kwargs self.current_arg = 0 def __call__(self, match_obj): # match_obj.group(1) is the contents of the parenthesis. # First we need to figure out whether it's a named or unnamed group. # grouped = match_obj.group(1) m = re.search(r'^\?P<(\w+)>(.*?)$', grouped) if m: # If this was a named group... # m.group(1) is the name of the group # m.group(2) is the regex. try: value = self.kwargs[m.group(1)] except KeyError: # It was a named group, but the arg was passed in as a # positional arg or not at all. try: value = self.args[self.current_arg] self.current_arg += 1 except IndexError: # The arg wasn't passed in. raise NoReverseMatch('Not enough positional arguments passed in') test_regex = m.group(2) else: # Otherwise, this was a positional (unnamed) group. try: value = self.args[self.current_arg] self.current_arg += 1 except IndexError: # The arg wasn't passed in. raise NoReverseMatch('Not enough positional arguments passed in') test_regex = grouped # Note we're using re.match here on purpose because the start of # to string needs to match. if not re.match(test_regex + '$', str(value)): # TODO: Unicode? raise NoReverseMatch("Value %r didn't match regular expression %r" % (value, test_regex)) return str(value) # TODO: Unicode? class RegexURLPattern: def __init__(self, regex, callback, default_args=None): # regex is a string representing a regular expression. Loading Loading @@ -58,12 +102,37 @@ class RegexURLPattern: except AttributeError, e: raise ViewDoesNotExist, "Tried %s in module %s. Error was: %s" % (func_name, mod_name, str(e)) def reverse(self, viewname, *args, **kwargs): if viewname != self.callback: raise NoReverseMatch return self.reverse_helper(*args, **kwargs) def reverse_helper(self, *args, **kwargs): """ Does a "reverse" lookup -- returns the URL for the given args/kwargs. The args/kwargs are applied to the regular expression in this RegexURLPattern. For example: >>> RegexURLPattern('^places/(\d+)/$').reverse_helper(3) 'places/3/' >>> RegexURLPattern('^places/(?P<id>\d+)/$').reverse_helper(id=3) 'places/3/' >>> RegexURLPattern('^people/(?P<state>\w\w)/(\w+)/$').reverse_helper('adrian', state='il') 'people/il/adrian/' Raises NoReverseMatch if the args/kwargs aren't valid for the RegexURLPattern. """ # TODO: Handle nested parenthesis in the following regex. result = re.sub(r'\(([^)]+)\)', MatchChecker(args, kwargs), self.regex.pattern) return result.replace('^', '').replace('$', '') class RegexURLResolver(object): def __init__(self, regex, urlconf_name): # regex is a string representing a regular expression. # urlconf_name is a string representing the module containing urlconfs. self.regex = re.compile(regex) self.urlconf_name = urlconf_name self.callback = None def resolve(self, path): tried = [] Loading Loading @@ -110,3 +179,12 @@ class RegexURLResolver(object): def resolve500(self): return self._resolve_special('500') def reverse(self, viewname, *args, **kwargs): for pattern in self.urlconf_module.urlpatterns: if pattern.callback == viewname: try: return pattern.reverse_helper(*args, **kwargs) except NoReverseMatch: continue raise NoReverseMatch