Ticket #2615: url_resolve.diff
File url_resolve.diff, 5.7 KB (added by , 18 years ago) |
---|
-
core/urlresolvers.py
17 17 class NoReverseMatch(Exception): 18 18 pass 19 19 20 class 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 20 45 def get_mod_func(callback): 21 46 # Converts 'django.views.news.stories.story_detail' to 22 47 # ['django.views.news.stories', 'story_detail'] 23 48 dot = callback.rindex('.') 24 49 return callback[:dot], callback[dot+1:] 25 50 26 def reverse_helper(regex, *args, **kwargs):51 def reverse_helper(regex, args, kwargs, default_args = None): 27 52 """ 28 53 Does a "reverse" lookup -- returns the URL for the given args/kwargs. 29 54 The args/kwargs are applied to the given compiled regular expression. … … 38 63 39 64 Raises NoReverseMatch if the args/kwargs aren't valid for the regex. 40 65 """ 66 41 67 # 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 {}) 44 74 45 75 class MatchChecker(object): 46 76 "Class used in reverse RegexURLPattern lookup." 47 77 def __init__(self, args, kwargs): 48 78 self.args, self.kwargs = args, kwargs 49 79 self.current_arg = 0 80 self.matched_kwargs = [] 50 81 51 82 def __call__(self, match_obj): 52 83 # match_obj.group(1) is the contents of the parenthesis. … … 59 90 # m.group(2) is the regex. 60 91 try: 61 92 value = self.kwargs[m.group(1)] 93 self.matched_kwargs.append(m.group(1)) 62 94 except KeyError: 63 95 # It was a named group, but the arg was passed in as a 64 96 # positional arg or not at all. … … 96 128 self._callback = None 97 129 self._callback_str = callback 98 130 self.default_args = default_args or {} 99 131 100 132 def resolve(self, path): 101 133 match = self.regex.search(path) 102 134 if match: … … 109 141 if not kwargs: 110 142 args = match.groups() 111 143 # In both cases, pass any extra_kwargs as **kwargs. 112 kwargs.update(self.default_args) 113 144 kwargs.update(self.default_args) 114 145 return self.callback, args, kwargs 115 146 116 147 def _get_callback(self): … … 134 165 raise NoReverseMatch 135 166 if lookup_view != self.callback: 136 167 raise NoReverseMatch 137 return self.reverse_helper( *args, **kwargs)168 return self.reverse_helper(args, kwargs) 138 169 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) 141 174 142 175 class RegexURLResolver(object): 143 176 def __init__(self, regex, urlconf_name, default_kwargs=None): … … 147 180 self.urlconf_name = urlconf_name 148 181 self.callback = None 149 182 self.default_kwargs = default_kwargs or {} 150 183 151 184 def resolve(self, path): 152 185 tried = [] 153 186 match = self.regex.search(path) … … 210 243 continue 211 244 elif pattern.callback == lookup_view: 212 245 try: 213 return pattern.reverse_helper( *args, **kwargs)246 return pattern.reverse_helper(args, kwargs , self.default_kwargs) 214 247 except NoReverseMatch: 215 248 continue 216 249 raise NoReverseMatch 217 250 218 251 def reverse_helper(self, lookup_view, *args, **kwargs): 219 252 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) 221 254 return result + sub_match 222 255 223 256 def resolve(path, urlconf=None): … … 227 260 resolver = RegexURLResolver(r'^/', urlconf) 228 261 return resolver.resolve(path) 229 262 230 def reverse (viewname, urlconf=None, args=None, kwargs=None):263 def reverse_match(viewname, urlconf=None, args=None, kwargs=None): 231 264 args = args or [] 232 265 kwargs = kwargs or {} 233 266 if urlconf is None: 234 267 from django.conf import settings 235 268 urlconf = settings.ROOT_URLCONF 236 269 resolver = RegexURLResolver(r'^/', urlconf) 237 return '/' + resolver.reverse(viewname, *args, **kwargs) 270 return resolver.reverse(viewname, *args, **kwargs) 271 272 def reverse(viewname, urlconf=None, args=None, kwargs=None): 273 return '/' + reverse_match(viewname, urlconf, args, kwargs).url