URL 路由 — Werkzeug 文档

来自菜鸟教程
Werkzeug/docs/2.0.x/routing
跳转至:导航、​搜索

URL路由

当涉及到组合多个控制器或视图函数时(不管你想如何调用它们),你需要一个调度程序。 一种简单的方法是在 PATH_INFO 上应用正则表达式测试并调用返回值的注册回调函数。

Werkzeug 提供了一个更强大的系统,类似于 Routes。 本页提到的所有对象必须从werkzeug.routing导入,而不是从werkzeug导入!

快速入门

这是一个简单的示例,它可以是博客的 URL 定义:

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 [f'Rule points to {endpoint!r} with arguments {args!r}']

那有什么作用呢? 首先我们创建一个新的 Map 来存储一堆 URL 规则。 然后我们向它传递一个 Rule 对象列表。

每个 Rule 对象都使用表示规则的字符串和端点进行实例化,端点将是规则所代表的视图的别名。 多个规则可以具有相同的端点,但应该具有不同的参数以允许 URL 构造。

URL 规则的格式很简单,但在下面详细解释。

在 WSGI 应用程序中,我们将 url_map 绑定到当前请求,它将返回一个新的 MapAdapter。 然后可以使用这个 url_map 适配器来匹配或构建当前请求的域。

然后,MapAdapter.match() 方法可以返回 (endpoint, args) 形式的元组或引发三个异常 NotFoundMethodNotAllowedRequestRedirect 之一]。 有关这些异常的更多详细信息,请查看 MapAdapter.match() 方法的文档。


规则格式

规则字符串是带有变量部分占位符的 URL 路径,格式为 <converter(arguments):name>converterarguments(带括号)是可选的。 如果没有给出转换器,则使用 default 转换器(默认为 string)。 下面讨论可用的转换器。

以斜线结尾的规则是“分支”,其他的是“叶子”。 如果 strict_slashes 启用(默认),访问没有斜杠的分支 URL 将重定向到附加斜杠的 URL。

许多 HTTP 服务器在接收请求时将连续的斜杠合并为一个。 如果启用 merge_slashes(默认),规则将在匹配和构建时合并非可变部分中的斜线。 访问带有连续斜杠的 URL 将重定向到合并了斜杠的 URL。 如果您想为 RuleMap 禁用 merge_slashes,您还需要适当地配置您的网络服务器。


内置转换器

常见类型的 URL 变量的转换器是内置的。 可用的转换器可以通过 Map.converters 覆盖或扩展。


地图、规则和适配器

规则工厂

规则模板

自定义转换器

您可以添加自定义转换器,以添加内置转换器未提供的行为。 要制作自定义转换器,子类 BaseConverter 然后将新类传递给 Map converters 参数,或将其添加到 url_map.converters

转换器应该有一个 regex 属性和一个匹配的正则表达式。 如果转换器可以在 URL 规则中接受参数,则它应该在其 __init__ 方法中接受它们。

它可以实现 to_python 方法将匹配的字符串转换为其他对象。 这也可以进行 regex 属性无法实现的额外验证,在这种情况下应该引发 werkzeug.routing.ValidationError。 引发任何其他错误将导致 500 错误。

它可以在构建 URL 时实现 to_url 方法将 Python 对象转换为字符串。 此处引发的任何错误都将转换为 werkzeug.routing.BuildError 并最终导致 500 错误。

此示例实现了一个 BooleanConverter,它将匹配字符串 "yes""no""maybe",返回 "maybe" 的随机值。

from random import randrange
from werkzeug.routing import BaseConverter, ValidationError

class BooleanConverter(BaseConverter):
    regex = r"(?:yes|no|maybe)"

    def __init__(self, url_map, maybe=False):
        super().__init__(url_map)
        self.maybe = maybe

    def to_python(self, value):
        if value == "maybe":
            if self.maybe:
                return not randrange(2)
            raise ValidationError
        return value == 'yes'

    def to_url(self, value):
        return "yes" if value else "no"

from werkzeug.routing import Map, Rule

url_map = Map([
    Rule("/vote/<bool:werkzeug_rocks>", endpoint="vote"),
    Rule("/guess/<bool(maybe=True):foo>", endpoint="guess")
], converters={'bool': BooleanConverter})

如果要更改默认转换器,请将不同的转换器分配给 "default" 键。


主机匹配

0.7 版中的新功能。


从 Werkzeug 0.7 开始,还可以对整个主机名进行匹配,而不仅仅是对子域进行匹配。 要启用此功能,您需要将 host_matching=True 传递给 Map 构造函数并向所有路由提供 host 参数:

url_map = Map([
    Rule('/', endpoint='www_index', host='www.example.com'),
    Rule('/', endpoint='help_index', host='help.example.com')
], host_matching=True)

可变部分当然也可以在主机部分:

url_map = Map([
    Rule('/', endpoint='www_index', host='www.example.com'),
    Rule('/', endpoint='user_index', host='<user>.example.com')
], host_matching=True)

网络套接字

1.0 版中的新功能。


如果 Rule 是用 websocket=True 创建的,它只会在 Map 绑定到 wsurl_scheme 的请求时匹配或 wss

笔记

除了路由之外,Werkzeug 没有进一步的 WebSocket 支持。 此功能主要用于 ASGI 项目。


url_map = Map([
    Rule("/ws", endpoint="comm", websocket=True),
])
adapter = map.bind("example.org", "/ws", url_scheme="ws")
assert adapter.match() == ("comm", {})

如果唯一匹配是 WebSocket 规则并且绑定是 HTTP(或者唯一匹配是 HTTP 并且绑定是 WebSocket),则会引发 WebsocketMismatch(派生自 BadRequest)异常。

由于 WebSocket URL 有不同的方案,规则总是用方案和主机构建,force_external=True 是隐含的。

url = adapter.build("comm")
assert url == "ws://example.org/ws"