zoukankan      html  css  js  c++  java
  • Werkzeug源码阅读笔记(四)

    今天主要讲一下werkzeug中的routing模块。这个模块是werkzeug中的重点模块,Flask中的路由相关的操作使用的都是这个模块

    routing模块的用法

    在讲解模块的源码之前,先讲讲这个模块怎么用。
    创建Map()对象:

    >>> m = Map([
    ...     # Static URLs
    ...     Rule('/', endpoint='static/index'),
    ...     Rule('/about', endpoint='static/about'),
    ...     Rule('/help', endpoint='static/help'),
    ...     # Knowledge Base
    ...     Subdomain('kb', [
    ...         Rule('/', endpoint='kb/index'),
    ...         Rule('/browse/', endpoint='kb/browse'),
    ...         Rule('/browse/<int:id>/', endpoint='kb/browse'),
    ...         Rule('/browse/<int:id>/<int:page>', endpoint='kb/browse')
    ...     ])
    ... ], default_subdomain='www')
    

    我们可以看到,一个Map中以列表的形式包含多个Rule. 示例里面还有个Subdomain,除了Subdomain名外,它里面以列表的形式包含多个Rule,如果没有Subdomain,后面的default_subdomain可以省略(default_subdomain适配于除了Subdomain之外的Rule部分)
    在创建了Map的实例后,我们可以为每个Subdomain创建URL适配器

    >>> c = m.bind('example.com')
    >>> c.build("kb/browse", dict(id=42))   #如果url有参数,使用dict()里面填参数名和值
    'http://kb.example.com/browse/42/'
    >>> c.build("kb/browse", dict())        #build接受的参数是endpoint,返回url地址
    'http://kb.example.com/browse/'
    >>> c.build("kb/browse", dict(id=42, page=3))
    'http://kb.example.com/browse/42/3'
    >>> c.build("static/about")
    '/about'
    >>> c.build("static/index", force_external=True)
    'http://www.example.com/'
    
    >>> c = m.bind('example.com', subdomain='kb')
    >>> c.build("static/about")
    'http://www.example.com/about'
    

    部分源码分析

    routing模块中有个RuleFactory类,提供了get_rules()工厂方法,该方法的设计目的是使得URL重用. 所有继承该类的类必须实现该方法
    比如Subdomain类:

    class Subdomain(RuleFactory):
        def __init__(self, subdomain, rules):
            self.subdomain = subdomain
            self.rules = rules
        def get_rules(self, map):
            for rulefactory in self.rules:
                for rule in rulefactory.get_rules(map):
                    rule = rule.empty()
                    rule.subdomain = self.subdomain
                    yield rule
    

    在该类中get_rules方法是一个生成器,调用一次返回一个subdomain中的rule,且该Rule未绑定.
    同理还有Submount,EndpointPrefix类,源码差不多,就不细讲了。只说下怎么用:
    Submount的用法:

    url_map = Map([
                Rule('/', endpoint='index'),
                Submount('/blog', [
                    Rule('/', endpoint='blog/index'),
                    Rule('/entry/<entry_slug>', endpoint='blog/show')
                ])
            ])
    

    把submount中第一个元素(路径)跟在原路径后,里面的Rule均以这个路径为挂载点
    这里当访问'blog/entry/<entry_slug>'就会找到'blog/show'这个endpoint;当访问'blog'就会找到'blog/index'这个endpoint

    EndpointPrefix的用法:

    url_map = Map([
                Rule('/', endpoint='index'),
                EndpointPrefix('blog/', [Submount('/blog', [
                    Rule('/', endpoint='index'),
                    Rule('/entry/<entry_slug>', endpoint='show')
                ])])
            ])
    

    和上一个示例等效,只不过是提取出了所有endpoint中相同的前缀放在前面

    Rule类

    在该类的实例中最重要的就是存储了URL地址。以下是它的构造方法的头部:

    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)
    
    

    在该类中,实现了bind方法,源码如下:

    def bind(self, map, rebind=False):
    	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()
    

    该方法的作用就是把Rule的实例绑定到一个Map实例上去

    Map类

    在该类的实例中,存储了很多个Rule类的实例,同时还有部分配置参数。以下是它的构造方法的头部:

    def __init__(self, rules=None, default_subdomain='', charset='utf-8',
                 strict_slashes=True, redirect_defaults=True,
                 converters=None, sort_parameters=False, sort_key=None,
                 encoding_errors='replace', host_matching=False)
    

    对照本文中开头的部分,可以发现rules参数是一个列表,该列表中包含了多个Rule的实例
    在该类中实现了几个重要的方法:

    • add()方法:它的作用是把一个Rule的实例添加到该Map实例中,并绑定。源码很简单:
    def add(self, rulefactory):
    	for rule in rulefactory.get_rules(self):   #获得rule实例
    		rule.bind(self)   #绑定该实例(源码见上面Rule类中的bind方法)
    		#在Map的_rules列表中加入该Rule实例,_rules用来装Map初始化函数中rules参数传进的Rules
    		self._rules.append(rule)   
    		self._rules_by_endpoint.setdefault(rule.endpoint, []).append(rule)
    	self._remap = True
    
    • bind()方法:返回一个MapAdapter类的实例,该类的作用是用来做URL的匹配。bind的头部为:
    bind(self, server_name, script_name=None, subdomain=None,
            url_scheme='http', default_method='GET', path_info=None,
            query_args=None)
    

    MapAdapter类

    该类用来做URL匹配。
    dispatcher()方法:该方法的作用是,传入path_info,该方法会使用match()方法找到对应的endpoint和相关参数,然后再把这个endpoint作为参数传入view_func视图函数中,返回一个view_func对象. 源码如下

    def dispatch(self, view_func, path_info=None, method=None,
                     catch_http_exceptions=False):
    	try:
    		try:
    			endpoint, args = self.match(path_info, method)  #获得endpoint和所需参数
    		except RequestRedirect as e:
    			return e
    		return view_func(endpoint, args)
    	except HTTPException as e:
    		if catch_http_exceptions:
    			return e
    		raise
    

    match()方法:该方法的作用是,传入path_infomethod,该方法会返回对应的endpoint和路径包含的参数,比如:

        >>> m = Map([
        ...     Rule('/', endpoint='index'),
        ...     Rule('/downloads/', endpoint='downloads/index'),
        ...     Rule('/downloads/<int:id>', endpoint='downloads/show')
        ... ])
        >>> urls = m.bind("example.com", "/")  #urls是MapAdapter对象
        >>> urls.match("/", "GET")
        ('index', {})
        >>> urls.match("/downloads/42")
        ('downloads/show', {'id': 42})
    

    build()方法:该方法与match()对应,传入endpoint和对应参数,返回path_info. 用法如下

        >>> m = Map([
        ...     Rule('/', endpoint='index'),
        ...     Rule('/downloads/', endpoint='downloads/index'),
        ...     Rule('/downloads/<int:id>', endpoint='downloads/show')
        ... ])
        >>> urls = m.bind("example.com", "/")
        >>> urls.build("index", {})
        '/'
        >>> urls.build("downloads/show", {'id': 42})
        '/downloads/42'
  • 相关阅读:
    现有某电商网站用户对商品的收藏数据,记录了用户收藏的商品id以及收藏日期,名为buyer_favorite1。 buyer_favorite1包含:买家id,商品id,收藏日期这三个字段,数据以“ ”分割
    面向对象程序设计中类与类的关系都有哪几种?分别用类图实例说明。
    Java为什么没有指针
    touchz,mkdir,vi的区别
    session使用方法
    迪杰斯特拉算法-文档读取数据
    数据结构---公交线路提示系统(Java后台+excel表格+web前端)
    caffe中train过程的train数据集、val数据集、test时候的test数据集区别
    caffe程序中出现的db.cpp:#line(行号) unknown database backend问题
    caffe的cancat层
  • 原文地址:https://www.cnblogs.com/eric-nirnava/p/werkzeug4.html
Copyright © 2011-2022 走看看