werkzeug/routing.py-Rule源码分析

Rule类主要用来定义和表示一个URL的模式。主要定义了一些关键字参数,用来改变url的行为。例如:这个url可以接收的请求方法,url的子域名,默认路径,端点名称,是否强制有斜杠在末尾等等

在最开始使用route()传递的option参数,最后都是传给了Rule这个类来处理的

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
源代码

参数解析:

  • string:一个有含有占位符的url路径(<converter(arguments):name>), converter是可选的(converter定义在Map里面),默认是字符串
  • defaults:可选项。在同一个endpoint下的一个字典格式的默认规则,如果你访问某个url的时候,这个url存在default配置,则会显示defaluts对用的url路径 例如:
 url_map = Map([
                Rule('/all/', defaults={'page': 1}, endpoint='all_entries'),
                Rule('/all/page/<int:page>', endpoint='all_entries')
            ])
# 当用户访问``http://example.com/all/page/1`` h将会重定向到``http://example.com/all/``.
  • subdomain:用来定义这个rule的子域名规则的一个字符串。默认是disable的,用法如下
url_map = Map([
                Rule('/', subdomain='<username>', endpoint='user/homepage'),
                Rule('/stats', subdomain='<username>', endpoint='user/stats')
            ])
  • methods:定义允许访问的方法。默认只允许get方法。在0.6.1版本中,会自动添加HEAD如果存在GET请求的话
  • bulid_only:True, 只创建url,而不会被匹配。一般用于静态文件的路径创建,不需要WSGI application处理的情况下
  • endpoint:这个url的端点名称,可以是任何类型。最好的选择是使用字符串表示,
  • strict_slashes:是否严格要求URL后面的斜杠。为这个URL重写Map里面的strict_slashes配置
  • redirect_to:重定向到其他地址。可以是一个字符串(其他url路径),也可以是一个可调用的对西对象。例如:
def foo_with_slug(adapter, id):
    # ask the database for the slug for the old id.  this of
    # course has nothing to do with werkzeug.
    return 'foo/' + Foo.get_slug_for_id(id)

url_map = Map([
    Rule('/foo/<slug>', endpoint='foo'),
    Rule('/some/old/url/<slug>', redirect_to='foo/<slug>'),  # 重定向到上面定义的路径
    Rule('/other/old/url/<int:id>', redirect_to=foo_with_slug)  # 重定向到foo_with_slug函数
])
  • alias:在同一个endpoint里面为rule serves定义一个别名
  • host:为整个host提供匹配规则。如果设置了host,则subdomain会是disabled状态

函数体解析:

 1    def __init__(self, string, defaults=None, subdomain=None, methods=None,
 2                  build_only=False, endpoint=None, strict_slashes=None,
 3                  redirect_to=None, alias=False, host=None):
 4         # 判断url路径是否是斜线开头
 5         if not string.startswith('/'):
 6             # 抛出异常:urls必须以斜线开头
 7             raise ValueError('urls must start with a leading slash')
 8         self.rule = string
 9         self.is_leaf = not string.endswith('/')
10 
11         self.map = None
12         self.strict_slashes = strict_slashes
13         self.subdomain = subdomain
14         self.host = host
15         self.defaults = defaults
16         self.build_only = build_only
17         self.alias = alias
18         # 对methods参数的判断
19         if methods is None:
20             self.methods = None
21         else:
22             if isinstance(methods, str):
23                 raise TypeError('param `methods` should be `Iterable[str]`, not `str`')
24             self.methods = set([x.upper() for x in methods])
25             # 如果没有HEAD和有GET的时候,把HEAD添加到methods里面
26             if 'HEAD' not in self.methods and 'GET' in self.methods:
27                 self.methods.add('HEAD')
28         self.endpoint = endpoint
29         self.redirect_to = redirect_to
30 
31         if defaults:
32             # 通过map对象以及str函数,取出defaulte中的每一个键,并设置成字符串格式。最终保存为set格式:{'abc'}
33             self.arguments = set(map(str, defaults))
34         else:
35             self.arguments = set()
36         self._trace = self._converters = self._regex = self._argument_weights = None

在Map对象的add方法中调用了Rule对象的get_rules方法

def get_rules(self, map):
    yield self

在Map对象的app方法中调用了Rule类的bind方法

这个方法主要用来绑定路由规则到map,并基于路由规则信息创建正则表达式

 1     def bind(self, map, rebind=False):
 2         # 判断这个rule的map属性是否已经被绑定过了map值
 3         if self.map is not None and not rebind:
 4             raise RuntimeError('url rule %r already bound to map %r' %
 5                                (self, self.map))
 6         # 把Map的对象赋值给self.map
 7         self.map = map
 8         # 判断属性,如果Rule对象中没有,则使用Map类中的
 9         if self.strict_slashes is None:
10             self.strict_slashes = map.strict_slashes
11         if self.subdomain is None:
12             self.subdomain = map.default_subdomain
13         # 调用Rule类的compile方法
14         self.compile()

bind方法最后调用了Rule类的compile方法

这个方法主要用来编译和存储正则表达式

原文地址:https://www.cnblogs.com/eric_yi/p/8325056.html