使用URL处理器

Changelog

0.7 新版功能.

Flask 0.7引入了URL处理器的概念。其想法是,您可能有一堆资源,其中包含URL中的公共部分,而您并不总是明确希望提供这些资源。例如,您可能有一组包含语言代码的URL,但您不希望自己在每个函数中处理它。

当与蓝图结合时,URL处理器特别有用。我们将在这里处理两个特定于应用程序的URL处理器以及蓝图细节。

国际化应用程序URL

考虑这样的应用程序:

from flask import Flask, g

app = Flask(__name__)

@app.route('/<lang_code>/')
def index(lang_code):
    g.lang_code = lang_code
    ...

@app.route('/<lang_code>/about')
def about(lang_code):
    g.lang_code = lang_code
    ...

这是非常多的重复,因为您必须处理 g 在每一个功能中反对自己。当然,可以使用一个修饰器来简化这个过程,但是如果您想从一个函数生成URL到另一个函数,您仍然需要显式地提供语言代码,这可能会很烦人。

对于后者,这里是 url_defaults() 函数进来了。它们可以自动将值注入到对的调用中 url_for() . 下面的代码检查语言代码是否还不在URL值字典中,以及端点是否需要一个名为 'lang_code' ::

@app.url_defaults
def add_language_code(endpoint, values):
    if 'lang_code' in values or not g.lang_code:
        return
    if app.url_map.is_endpoint_expecting(endpoint, 'lang_code'):
        values['lang_code'] = g.lang_code

方法:URL映射的meth:`~werkzeug.routing.Map.is_endpoint_expecting`可用于确定为给定端点提供语言代码是否有意义。

这个函数的逆函数是 url_value_preprocessor() 它们在请求匹配后立即执行,并且可以根据URL值执行代码。他们的想法是从价值词典中提取信息并将其放在其他地方:

@app.url_value_preprocessor
def pull_lang_code(endpoint, values):
    g.lang_code = values.pop('lang_code', None)

这样你就不用再做了 lang_code 指派给 g 在每个功能中。您可以通过编写自己的装饰器来进一步改进这一点,该装饰器以语言代码作为URL的前缀,但更漂亮的解决方案是使用蓝图。一旦 'lang_code' 从值字典中弹出,它将不再转发到视图函数,将代码缩减为:

from flask import Flask, g

app = Flask(__name__)

@app.url_defaults
def add_language_code(endpoint, values):
    if 'lang_code' in values or not g.lang_code:
        return
    if app.url_map.is_endpoint_expecting(endpoint, 'lang_code'):
        values['lang_code'] = g.lang_code

@app.url_value_preprocessor
def pull_lang_code(endpoint, values):
    g.lang_code = values.pop('lang_code', None)

@app.route('/<lang_code>/')
def index():
    ...

@app.route('/<lang_code>/about')
def about():
    ...

国际化蓝图URL

因为蓝图可以用一个公共字符串自动为所有URL加前缀,所以很容易为每个函数自动加前缀。此外,蓝图可以有每个蓝图的URL处理器,它从 url_defaults() 函数,因为它不再需要检查URL是否真的对 'lang_code' 参数::

from flask import Blueprint, g

bp = Blueprint('frontend', __name__, url_prefix='/<lang_code>')

@bp.url_defaults
def add_language_code(endpoint, values):
    values.setdefault('lang_code', g.lang_code)

@bp.url_value_preprocessor
def pull_lang_code(endpoint, values):
    g.lang_code = values.pop('lang_code')

@bp.route('/')
def index():
    ...

@bp.route('/about')
def about():
    ...