for item in _converter_args_re.finditer(argstr): value = item.group('stringval') if value isNone: value = item.group('value') value = _pythonize(value) ifnot item.group('name'): args.append(value) else: name = item.group('name') kwargs[name] = value
returntuple(args), kwargs
defparse_rule(rule): """Parse a rule and return it as generator. Each iteration yields tuples in the form ``(converter, arguments, variable)``. If the converter is `None` it's a static url part, otherwise it's a dynamic one. :internal: """ pos = 0 end = len(rule) do_match = _rule_re.match used_names = set() while pos < end: m = do_match(rule, pos) if m isNone: break data = m.groupdict() if data['static']: yieldNone, None, data['static'] variable = data['variable'] converter = data['converter'] or'default' if variable in used_names: raise ValueError('variable name %r used twice.' % variable) used_names.add(variable) yield converter, data['args'] orNone, variable pos = m.end() if pos < end: remaining = rule[pos:] if'>'in remaining or'<'in remaining: raise ValueError('malformed url rule: %r' % rule) yieldNone, None, remaining
defget_converter(self, variable_name, converter_name, args, kwargs): """Looks up the converter for the given parameter. .. versionadded:: 0.9 """ if converter_name notin self.map.converters: raise LookupError('the converter %r does not exist' % converter_name) return self.map.converters[converter_name](self.map, *args, **kwargs)
以我们之前的 demo 为例,
1 2 3 4 5 6 7 8 9 10
from flask import Flask from werkzeug.routing import BaseConverter classRegexConverter(BaseConverter): def__init__(self, map, *args): self.map = map self.regex = args[0]
defmatch(self, path, method=None): """Check if the rule matches a given path. Path is a string in the form ``"subdomain|/path"`` and is assembled by the map. If the map is doing host matching the subdomain part will be the host instead. If the rule matches a dict with the converted values is returned, otherwise the return value is `None`. :internal: """ ifnot self.build_only: m = self._regex.search(path) if m isnotNone: groups = m.groupdict() # we have a folder like part of the url without a trailing # slash and strict slashes enabled. raise an exception that # tells the map to redirect to the same url but with a # trailing slash if self.strict_slashes andnot self.is_leaf and \ not groups.pop('__suffix__') and \ (method isNoneor self.methods isNoneor method in self.methods): raise RequestSlash() # if we are not in strict slashes mode we have to remove # a __suffix__ elifnot self.strict_slashes: del groups['__suffix__']
result = {} for name, value in iteritems(groups): try: value = self._converters[name].to_python(value) except ValidationError: return result[str(name)] = value if self.defaults: result.update(self.defaults)
if self.alias and self.map.redirect_defaults: raise RequestAliasRedirect(result)
return result
这也是 werkzurg 框架的 routing 文件中 Rule 类种的一部分的源码,在这段代码中,首先利用 re 对象中的 search 方法,检测当前传入的 Path 是否匹配,如果匹配的话,进入后续的处理流程,还记得我们之前最终生成的 /docs/model_utils/(?P<url>.*) 么,这里面利用了正则表达式命名组的语法糖,在这里,匹配成功后,Python 的 re 库里给我们提供了一个 groupdict 让我们取出命名组里所代表的值。然后我们调用 conveter 实例里面的 to_python 方法来对我们匹配出来的值进行处理(注:这是 Converter 系列对象中的一个可重载方法,我们可以通过重载这个方法,来对我们匹配到的值进行一些逻辑处理,这个我们还是后面再讲吧,flag++),然后我们把最终的 result 值返回。
defdispatch_request(self): """Does the request dispatching. Matches the URL and returns the return value of the view or error handler. This does not have to be a response object. In order to convert the return value to a proper response object, call :func:`make_response`. .. versionchanged:: 0.7 This no longer does the exception handling, this code was moved to the new :meth:`full_dispatch_request`. """ req = _request_ctx_stack.top.request if req.routing_exception isnotNone: self.raise_routing_exception(req) rule = req.url_rule # if we provide automatic options for this URL and the # request came with the OPTIONS method, reply automatically ifgetattr(rule, 'provide_automatic_options', False) \ and req.method == 'OPTIONS': return self.make_default_options_response() # otherwise dispatch to the handler for that endpoint return self.view_functions[rule.endpoint](**req.view_args)