今天主要讲一下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'

Werkzeug源码阅读笔记(四)的更多相关文章

  1. werkzeug源码阅读笔记(二) 下

    wsgi.py----第二部分 pop_path_info()函数 先测试一下这个函数的作用: >>> from werkzeug.wsgi import pop_path_info ...

  2. Werkzeug源码阅读笔记(三)

    这次主要讲下werkzeug中的Local. 源码在werkzeug/local.py Thread Local 在Python中,状态是保存在对象中.Thread Local是一种特殊的对象,它是对 ...

  3. werkzeug源码阅读笔记(二) 上

    因为第一部分是关于初始化的部分的,我就没有发布出来~ wsgi.py----第一部分 在分析这个模块之前, 需要了解一下WSGI, 大致了解了之后再继续~ get_current_url()函数 很明 ...

  4. Mina源码阅读笔记(四)—Mina的连接IoConnector2

    接着Mina源码阅读笔记(四)-Mina的连接IoConnector1,,我们继续: AbstractIoAcceptor: 001 package org.apache.mina.core.rewr ...

  5. 源码阅读笔记 - 1 MSVC2015中的std::sort

    大约寒假开始的时候我就已经把std::sort的源码阅读完毕并理解其中的做法了,到了寒假结尾,姑且把它写出来 这是我的第一篇源码阅读笔记,以后会发更多的,包括算法和库实现,源码会按照我自己的代码风格格 ...

  6. jdk源码阅读笔记-LinkedHashMap

    Map是Java collection framework 中重要的组成部分,特别是HashMap是在我们在日常的开发的过程中使用的最多的一个集合.但是遗憾的是,存放在HashMap中元素都是无序的, ...

  7. HashMap源码阅读笔记

    HashMap源码阅读笔记 本文在此博客的内容上进行了部分修改,旨在加深笔者对HashMap的理解,暂不讨论红黑树相关逻辑 概述   HashMap作为经常使用到的类,大多时候都是只知道大概原理,比如 ...

  8. guavacache源码阅读笔记

    guavacache源码阅读笔记 官方文档: https://github.com/google/guava/wiki/CachesExplained 中文版: https://www.jianshu ...

  9. 【原】AFNetworking源码阅读(四)

    [原]AFNetworking源码阅读(四) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇还遗留了很多问题,包括AFURLSessionManagerTaskDe ...

随机推荐

  1. zoj1136 Multiple

    记忆化搜索,因为要求最小的,肯定是从小到大,依次添加,那么通过bfs,队列貌似是最好的选择.因为很可能那个数爆long long,所以采用字符串存储,并记录余数,通过模拟除法的方式来写. 剪枝:因为后 ...

  2. 阿牛的EOF牛肉串

    #include <iostream>using namespace std;long long s0,s1,s2,s3;int main(){ int i,n; while(cin> ...

  3. (转)对mysql explain讲的比较清楚的

    转自:http://www.blogjava.net/persister/archive/2008/10/27/236813.html 在 explain的帮助下,您就知道什么时候该给表添加索引,以使 ...

  4. [ZT]图像处理库的比较:OpenCV,FreeImage,CImg,CxImage

    1.对OpenCV 的印象:功能十分的强大,而且支持目前先进的图像处理技术,体系十分完善,操作手册很详细,手册首先给大家补计算机视觉的知识,几乎涵盖了近10年内的主流算法: 然后将图像格式和矩阵运算, ...

  5. 十个最值得阅读学习的C开源项目代码

    1. Webbench Webbench 是一个在linux下使用的非常简单的网站压测工具.它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作的性能,最多可以 模拟3万个并 ...

  6. linux 下访问mysql

    1:先进到root:/# /usr/local/mysql/bin/2:root:/# mysql -u root -p     Enter password:

  7. Python入门之中文乱码

    python入门编码: Python 文件中如果未指定编码,有中文代码时候,在执行过程会出现报错: File "test.py", line 2 SyntaxError: Non- ...

  8. ajax查询数据的举例

    1.根据下拉框的值异步查询信息 HTML代码如下: <script> $(function(){ //页面载入时执行 $("#key").change(function ...

  9. 通宵疯狂积累VB.NET基础知识

    VB.NET中Module的概念 为什么VB.NET中会有一个Module的东西,而在C#等语言中是没有的 首先,这是一个历史原因.早先的VB语言都有模块和类模块的概念.所谓模块一般就是存放公用的一些 ...

  10. android-Java SoftReference,WeakReference,Direct Reference简介

    主要部分: SoftReference(软引用)是java中一个用来实现缓存内容的类.通过此类,可以观察某对象什么时候会被垃圾收集的执行绪清除.被 Soft Reference 指到的对象,即使没有任 ...