flask中路由的本质源码分析
flask中url的本质:
吧url和视图函数封装到一个Rule对象里面去了,并且吧这个对象添加到url_map中
Rule={"url":'/index','method':'index'}
url_map = [{"url":'/index','method':'index'},{"url":'/index','method':'index'}]
第一步:
app = Flask(__name__)
第二步:实例化一个对象,执行构造方法
if self.has_static_folder:
self.add_url_rule(self.static_url_path + '/<path:filename>',
endpoint='static',
view_func=self.send_static_file)
第三步:
@setupmethod
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
#吧url和视图函数保存到了一个Rule对象中,并且把这个对象添加到了url_map列表中
rule = self.url_rule_class(rule, methods=methods, **options)
rule.provide_automatic_options = provide_automatic_options self.url_map.add(rule)
第四步:
url_rule_class = Rule @implements_to_string
class Rule(RuleFactory): def __init__(self, string, defaults=None, subdomain=None, methods=None,
build_only=False, endpoint=None, strict_slashes=None,
redirect_to=None, alias=False, host=None):
if not string.startswith('/'):
raise ValueError('urls must start with a leading slash')
self.rule = string
self.is_leaf = not string.endswith('/') self.map = None
self.strict_slashes = strict_slashes
self.subdomain = subdomain
self.host = host
self.defaults = defaults
self.build_only = build_only
self.alias = alias
if methods is None:
self.methods = None
else:
if isinstance(methods, str):
raise TypeError('param `methods` should be `Iterable[str]`, not `str`')
self.methods = set([x.upper() for x in methods])
if 'HEAD' not in self.methods and 'GET' in self.methods:
self.methods.add('HEAD')
self.endpoint = endpoint
self.redirect_to = redirect_to if defaults:
self.arguments = set(map(str, defaults))
else:
self.arguments = set()
self._trace = self._converters = self._regex = self._argument_weights = None def empty(self):
"""
Return an unbound copy of this rule. This can be useful if want to reuse an already bound URL for another
map. See ``get_empty_kwargs`` to override what keyword arguments are
provided to the new copy.
"""
return type(self)(self.rule, **self.get_empty_kwargs()) def get_empty_kwargs(self):
"""
Provides kwargs for instantiating empty copy with empty() Use this method to provide custom keyword arguments to the subclass of
``Rule`` when calling ``some_rule.empty()``. Helpful when the subclass
has custom keyword arguments that are needed at instantiation. Must return a ``dict`` that will be provided as kwargs to the new
instance of ``Rule``, following the initial ``self.rule`` value which
is always provided as the first, required positional argument.
"""
defaults = None
if self.defaults:
defaults = dict(self.defaults)
return dict(defaults=defaults, subdomain=self.subdomain,
methods=self.methods, build_only=self.build_only,
endpoint=self.endpoint, strict_slashes=self.strict_slashes,
redirect_to=self.redirect_to, alias=self.alias,
host=self.host) def get_rules(self, map):
yield self def refresh(self):
"""Rebinds and refreshes the URL. Call this if you modified the
rule in place. :internal:
"""
self.bind(self.map, rebind=True) def bind(self, map, rebind=False):
"""Bind the url to a map and create a regular expression based on
the information from the rule itself and the defaults from the map. :internal:
"""
if self.map is not None and not rebind:
raise RuntimeError('url rule %r already bound to map %r' %
(self, self.map))
self.map = map
if self.strict_slashes is None:
self.strict_slashes = map.strict_slashes
if self.subdomain is None:
self.subdomain = map.default_subdomain
self.compile() def get_converter(self, variable_name, converter_name, args, kwargs):
"""Looks up the converter for the given parameter. .. versionadded:: 0.9
"""
if converter_name not in self.map.converters:
raise LookupError('the converter %r does not exist' % converter_name)
return self.map.converters[converter_name](self.map, *args, **kwargs) def compile(self):
"""Compiles the regular expression and stores it."""
assert self.map is not None, 'rule not bound' if self.map.host_matching:
domain_rule = self.host or ''
else:
domain_rule = self.subdomain or '' self._trace = []
self._converters = {}
self._static_weights = []
self._argument_weights = []
regex_parts = [] def _build_regex(rule):
index = 0
for converter, arguments, variable in parse_rule(rule):
if converter is None:
regex_parts.append(re.escape(variable))
self._trace.append((False, variable))
for part in variable.split('/'):
if part:
self._static_weights.append((index, -len(part)))
else:
if arguments:
c_args, c_kwargs = parse_converter_args(arguments)
else:
c_args = ()
c_kwargs = {}
convobj = self.get_converter(
variable, converter, c_args, c_kwargs)
regex_parts.append('(?P<%s>%s)' % (variable, convobj.regex))
self._converters[variable] = convobj
self._trace.append((True, variable))
self._argument_weights.append(convobj.weight)
self.arguments.add(str(variable))
index = index + 1 _build_regex(domain_rule)
regex_parts.append('\\|')
self._trace.append((False, '|'))
_build_regex(self.is_leaf and self.rule or self.rule.rstrip('/'))
if not self.is_leaf:
self._trace.append((False, '/')) if self.build_only:
return
regex = r'^%s%s$' % (
u''.join(regex_parts),
(not self.is_leaf or not self.strict_slashes) and
'(?<!/)(?P<__suffix__>/?)' or ''
)
self._regex = re.compile(regex, re.UNICODE) def match(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:
"""
if not self.build_only:
m = self._regex.search(path)
if m is not None:
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 and not self.is_leaf and \
not groups.pop('__suffix__') and \
(method is None or self.methods is None or
method in self.methods):
raise RequestSlash()
# if we are not in strict slashes mode we have to remove
# a __suffix__
elif not 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 def build(self, values, append_unknown=True):
"""Assembles the relative url for that rule and the subdomain.
If building doesn't work for some reasons `None` is returned. :internal:
"""
tmp = []
add = tmp.append
processed = set(self.arguments)
for is_dynamic, data in self._trace:
if is_dynamic:
try:
add(self._converters[data].to_url(values[data]))
except ValidationError:
return
processed.add(data)
else:
add(url_quote(to_bytes(data, self.map.charset), safe='/:|+'))
domain_part, url = (u''.join(tmp)).split(u'|', 1) if append_unknown:
query_vars = MultiDict(values)
for key in processed:
if key in query_vars:
del query_vars[key] if query_vars:
url += u'?' + url_encode(query_vars, charset=self.map.charset,
sort=self.map.sort_parameters,
key=self.map.sort_key) return domain_part, url def provides_defaults_for(self, rule):
"""Check if this rule has defaults for a given rule. :internal:
"""
return not self.build_only and self.defaults and \
self.endpoint == rule.endpoint and self != rule and \
self.arguments == rule.arguments def suitable_for(self, values, method=None):
"""Check if the dict of values has enough data for url generation. :internal:
"""
# if a method was given explicitly and that method is not supported
# by this rule, this rule is not suitable.
if method is not None and self.methods is not None \
and method not in self.methods:
return False defaults = self.defaults or () # all arguments required must be either in the defaults dict or
# the value dictionary otherwise it's not suitable
for key in self.arguments:
if key not in defaults and key not in values:
return False # in case defaults are given we ensure taht either the value was
# skipped or the value is the same as the default value.
if defaults:
for key, value in iteritems(defaults):
if key in values and value != values[key]:
return False return True def match_compare_key(self): return bool(self.arguments), -len(self._static_weights), self._static_weights,\
-len(self._argument_weights), self._argument_weights def build_compare_key(self):
"""The build compare key for sorting. :internal:
"""
return self.alias and 1 or 0, -len(self.arguments), \
-len(self.defaults or ()) def __eq__(self, other):
return self.__class__ is other.__class__ and \
self._trace == other._trace __hash__ = None def __ne__(self, other):
return not self.__eq__(other) def __str__(self):
return self.rule @native_string_result
def __repr__(self):
if self.map is None:
return u'<%s (unbound)>' % self.__class__.__name__
tmp = []
for is_dynamic, data in self._trace:
if is_dynamic:
tmp.append(u'<%s>' % data)
else:
tmp.append(data)
return u'<%s %s%s -> %s>' % (
self.__class__.__name__,
repr((u''.join(tmp)).lstrip(u'|')).lstrip(u'u'),
self.methods is not None
and u' (%s)' % u', '.join(self.methods)
or u'',
self.endpoint
)
flask中路由的本质源码分析的更多相关文章
- RocketMQ中PullConsumer的启动源码分析
通过DefaultMQPullConsumer作为默认实现,这里的启动过程和Producer很相似,但相比复杂一些 [RocketMQ中Producer的启动源码分析] DefaultMQPullCo ...
- Netty中NioEventLoopGroup的创建源码分析
NioEventLoopGroup的无参构造: public NioEventLoopGroup() { this(0); } 调用了单参的构造: public NioEventLoopGroup(i ...
- RocketMQ中Broker的启动源码分析(一)
在RocketMQ中,使用BrokerStartup作为启动类,相较于NameServer的启动,Broker作为RocketMQ的核心可复杂得多 [RocketMQ中NameServer的启动源码分 ...
- RocketMQ中Broker的启动源码分析(二)
接着上一篇博客 [RocketMQ中Broker的启动源码分析(一)] 在完成准备工作后,调用start方法: public static BrokerController start(Broker ...
- RocketMQ中Broker的消息存储源码分析
Broker和前面分析过的NameServer类似,需要在Pipeline责任链上通过NettyServerHandler来处理消息 [RocketMQ中NameServer的启动源码分析] 实际上就 ...
- JDK中String类的源码分析(二)
1.startsWith(String prefix, int toffset)方法 包括startsWith(*),endsWith(*)方法,都是调用上述一个方法 public boolean s ...
- Springboot中mybatis执行逻辑源码分析
Springboot中mybatis执行逻辑源码分析 在上一篇springboot整合mybatis源码分析已经讲了我们的Mapper接口,userMapper是通过MapperProxy实现的一个动 ...
- Flask系列10-- Flask请求上下文源码分析
总览 一.基础准备. 1. local类 对于一个类,实例化得到它的对象后,如果开启多个线程对它的属性进行操作,会发现数据时不安全的 import time from threading import ...
- Flask - 请求处理流程和上下文源码分析
目录 Flask - 请求处理流程和上下文 WSGI Flask的上下文对象及源码解析 0. 请求入口 1.请求上下文对象的创建 2. 将请求上下文和应用上下文入栈 3.根据请求的URl执行响应的视图 ...
随机推荐
- 转:VS2013快捷键大全
Ctrl+E,D ----格式化全部代码 Ctrl+E,F ----格式化选中的代码 CTRL + SHIFT + B生成解决方案 CTRL + F7 生成编译 CTRL + O 打开文件 CTRL ...
- Android学习笔记三:用Intent串联activity
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/7513399.html 一:Intent Intent可以理解为 意图. 我们可以通过创建intent实例来定义 ...
- cocos2d-js 3.0 屏幕适配方案 分辨率适应
首先介绍一个api和相应的参数: cc.view.setDesignResolutionSize(1024, 768, cc.ResolutionPolicy.FIXED_WIDTH); 这里设置游戏 ...
- 【Excle】一个比VLOOKUP牛的函数LOOKUP
1.根据时间查找最近发生的交易 2.多条件查找 3.反向查找 4.模糊匹配 上述例子充分说明了LOOKUP的查找特技,点击下载上述案例对应的Excle
- 链接sql数据库并输出csv文件
__author__ = 'chunyang.wu' #作者:SelectDB # -*- coding: utf-8 -*- import MySQLdb import os os.environ[ ...
- java中pojo、dao命名解释
POJO::POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans,是为了避免和EJB混淆所创造的简称. 使用POJO名称是为了避免和EJB ...
- Eclipse和MyEclipse使用技巧--Eclipse中使用Git-让版本管理更简单
详细步骤: 第一部分 GIT介绍 (1)GIT往世今生 2005年开发Samba的Andrew试图破解BitKeeper(一款商业的版本控制系统)的协议(这么干的其实也不只他一个),被BitMove ...
- ACM退役前2个月总结
这个时候是该好好地反省一下自己了!曾经的时候为了队伍能打出很多其它的题,我硬是看了ACM的非常多模块!也会了非常多的模板!可是如今我痛苦地发现比赛还是我一人单挑的局面!如今我也遇见了一个瓶颈了,那就是 ...
- 代理Proxy初探
Proxy,也就是"代理"了. 意思就是.你不用去做,别人取代你去处理.比方说:租房.你仅仅要找到"我爱我家"中介,把全部的事情交给他们去代劳, "我 ...
- 【AI】Computing Machinery and Intelligence - 计算机器与智能
[论文标题] Computing Machinery and Intelligence (1950) [论文作者] A. M. Turing (Alan Mathison Turing) [论文链接] ...