Werkzeug 之URL 路由

Werkzeug 之URL 路由

原文链接http://werkzeug.pocoo.org/docs/0.12/routing/
当需要组合控制器和视图函数时,我们需要一个调度器来实现。一个简单的实现方式是采用正则表达式匹测试路由信息,调用回调函数并返回结果。
Werkzeug 提供了一个类似Route[1]的强大功能.下文提到的所有对象都是从
werkzeug.routing 导入而不是 werkzeug

快速指南

from werkzeug.routing import Map, Rule, NotFound, RequestRedirect
url_map = Map([
    Rule('/', endpoint='blog/index'),
    Rule('/<int:year>/', endpoint='blog/archive'),
    Rule('/<int:year>/<int:month>/',
        endpoint='blog/archive'),
    Rule('/<int:year>/<int:month>/<int:day>/', endpoint='blog/archive'),
    Rule('/<int:year>/<int:month>/<int:day>/<slug>',
         endpoint='blog/show_post'),
    Rule('/about', endpoint='blog/about_me'),
    Rule('/feeds/', endpoint='blog/feeds'),
    Rule('/feeds/<feed_name>.rss', endpoint='blog/show_feed')
])

def application(environ, start_response):
    urls = url_map.bind_to_environ(environ)
    try:
        endpoint, args = urls.match()
    except HTTPException, e:
        return e(environ, start_response)
    start_response('200 OK', [('Content-Type', 'text/plain')])
    return ['Rule points to %r with arguments %r' % (endpoint, args)]

上面代码的主要功能:首先我们创建一个Map对象来存储URL规则(Rule),其中Rule对象是以列表的形式放到Map中的。
每个Rule对象是一个字符串实例。这个字符串由一条规则和一个endpoint组成。endpoint的本质是rule所表示的视图的别名。多条rule可以对应一个endpoint,但必须是不同的参数构成的URL语句。

在WSGI应用中我们绑定url_map 和request对象,并返回一个新的 MapAdapter对象。此url_map 适配器通常用于为request匹配域名或生成域名。
方法MapAdapter.match()返回(endpoint, args)形式的元组,或者抛出异常: NotFound, MethodNotAllowed, 或RequestRedirect。

Maps, Rules and Adapters

class werkzeug.routing.Map

Map类存储所有URL 规则和一些配置参数。影响程序全局路由规则的参数只能配置在Map实例之中。而其他的参数默认可以被每个规则重写。

class werkzeug.routing.MapAdapter
MapAdapter.build()

build方法接收force_external 参数,如果将其设置为True会显示完整的外部URL。只有当目标URL在
不同的子域名才会使用。

>>> 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'
>>> urls.build("downloads/show", {'id': 42}, force_external=True)
'http://example.com/downloads/42'

由于URL不包含非ASCII数据,因此其总是返回字节形式的字符串。
附带的值会转换成unicode码附加在URL后边:

>>> urls.build("index", {'q': 'My Searchstring'})
'/?q=My+Searchstring'

在处理附加参数时,list会被解释成多值的形式:

>>> urls.build("index", {'q': ['a', 'b', 'c']})
'/?q=a&q=b&q=c'
MapAdapter.dispatch(view_func, path_info=None, method=None, catch_http_exceptions=False)

完成分发处理功能。调用视图函数view_func,view_func的入参是endpoint 和一个字典参数。dispatch方法实现view函数查找,调用,并返回一个response对象或WSGI应用。
一个简单的dispatch 用法实例:

from werkzeug.wrappers import Request, Response
from werkzeug.wsgi import responder
from werkzeug.routing import Map, Rule
def on_index(request):
    return Response('Hello from the index')
url_map = Map([Rule('/', endpoint='index')])
views = {'index': on_index}
@responder
def application(environ, start_response):
    request = Request(environ)
    urls = url_map.bind_to_environ(environ)
    return urls.dispatch(lambda e, v: views[e](request, **v),
                         catch_http_exceptions=True)
if__name__=='__main__':
    fromwerkzeug.servingimportrun_simple
    run_simple('localhost',4000,application)
MapAdapter.match()

路由规则匹配方法。
匹配举例如下:

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

URLs丢失的例子

>> urls.match("/downloads")
Traceback (most recent call last):
  ...
RequestRedirect: http://example.com/downloads/
>>> urls.match("/missing")
Traceback (most recent call last):
  ...
NotFound: 404 Not Found
class werkzeug.routing.Rule

Rule代表一种URL模式。入参endpoint可以使任意对象,例如一个方法的引用,字符或者数字等等。推荐使用字符串,因为endpoint通常用于URL生成。

Rule 工厂类

class werkzeug.routing.RuleFactory
在实现复杂URL配置时,可以通过继承RuleFactory来避免重复的工作
class werkzeug.routing.Subdomain(subdomain, rules)
子域名配置
In [7]: from werkzeug.routing import *

In [8]: url_map = Map([
   ...:     Rule('/', endpoint='#select_language'),
   ...:     Subdomain('<string(length=2):lang_code>', [
   ...:         Rule('/', endpoint='index'),
   ...:         Rule('/about', endpoint='about'),
   ...:         Rule('/help', endpoint='help')
   ...:     ])
   ...: ])

In [9]: url_map
Out[9]:
Map([<Rule '/' -> #select_language>,
 <Rule '<lang_code>|/about' -> about>,
 <Rule '<lang_code>|/help' -> help>,
 <Rule '<lang_code>|/' -> index>])
class werkzeug.routing.Submount(path, rules)
与Subdomain类似,只不过URL前缀是给定的字符串
In [10]: url_map = Map([
    ...:     Rule('/', endpoint='index'),
    ...:     Submount('/blog', [
    ...:         Rule('/', endpoint='blog/index'),
    ...:         Rule('/entry/<entry_slug>', endpoint='blog/show')
    ...:     ])
    ...: ])

In [11]: url_map
Out[11]:
Map([<Rule '/blog/' -> blog/index>,
 <Rule '/' -> index>,
 <Rule '/blog/entry/<entry_slug>' -> blog/show>])
class werkzeug.routing.EndpointPrefix(prefix, rules)
EndpointPrefix前缀是给定的字符串
In [13]: url_map = Map([
    ...:     Rule('/', endpoint='index'),
    ...:     EndpointPrefix('blog/', [Submount('/blog', [
    ...:         Rule('/', endpoint='index'),
    ...:         Rule('/entry/<entry_slug>', endpoint='show')
    ...:     ])])
    ...: ])

In [14]: url_map
Out[14]:
Map([<Rule '/blog/' -> blog/index>,
 <Rule '/' -> index>,
 <Rule '/blog/entry/<entry_slug>' -> blog/show>])

Rule 模板

class werkzeug.routing.RuleTemplate(rules)

举例:

from werkzeug.routing import Map, Rule, RuleTemplate
resource = RuleTemplate([
    Rule('/$name/', endpoint='$name.list'),
    Rule('/$name/<int:id>', endpoint='$name.show')
])
url_map = Map([resource(name='user'), resource(name='page')])

实现Rule规则的参数化。

Custom Converters(定制转换器)

通过继承BaseConverter并传入新的Converters和url_map参数来实现定制的转换器。
举例:

from random import randrange
from werkzeug.routing import Rule, Map, BaseConverter, ValidationError
class BooleanConverter(BaseConverter):
def __init__(self, url_map, randomify=False):
   super(BooleanConverter, self).__init__(url_map)
   self.randomify = randomify
   self.regex = '(?:yes|no|maybe)'
def to_python(self, value):
        if value == 'maybe':
            if self.randomify:
                return not randrange(2)
            raise ValidationError()
        return value == 'yes'
def to_url(self, value):
        return value and 'yes' or 'no'
url_map = Map([
    Rule('/vote/<bool:werkzeug_rocks>', endpoint='vote'),
    Rule('/vote/<bool(randomify=True):foo>', endpoint='foo')
], converters={'bool': BooleanConverter})

[1]http://routes.readthedocs.io/en/latest/

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值