www.zhblog.net

Flask Url处理

在项目中,我们经常有这样的需求:如国际化,根据语言返回不同的视图模板;如果页面分PC和手机端2套页面模板,那么也需要根据不同客户端请求返回不同的视图模板。

在每个视图方法中写同样的逻辑分别处理是可行,但是不合理的。

例如:根据不同的语言返回不同的视图页面。

@app.route('/<lang_code>/index')
def index(lang_code):
    if lang_code == 'en':
        return render_template('url_processors/index_en.html')
    if lang_code == 'cn':
        return render_template('url_processors/index_cn.html')


@app.route('/<lang_code>/about')
def about(lang_code):
    if lang_code == 'en':
        return render_template('url_processors/about_en.html')
    if lang_code == 'cn':
        return render_template('url_processors/about_cn.html')


1.用装饰器decorate处理相同的逻辑,返回不同的页面

def lang_decorate(func):
    @functools.wraps(func)
    def vf(*keys, **args):
        if args['lang_code']:
            g.lang_code = args['lang_code']
        return func(*keys, **args)
    return vf

@app.route('/<lang_code>/index')
@lang_decoratedef index(lang_code):
    return render_template('url_processors/index_{}.html'.format(g.lang_code))
    # if lang_code == 'en':    
    #     return render_template('url_processors/index_en.html')    
    # if lang_code == 'cn':    
    #     return render_template('url_processors/index_cn.html')

@app.route('/<lang_code>/about')
@lang_decoratedef about(lang_code):
    return render_template('url_processors/about_{}.html'.format(g.lang_code))
    # if lang_code == 'en':    
    #     return render_template('url_processors/about_en.html')    
    # if lang_code == 'cn':    
    #     return render_template('url_processors/about_cn.html')


这个例子没什么用,因为不用装饰器也可以直接写成这样。这里只是为说明而使用。


2.用url_defaults()和url_value_preprocessor()进行url处理

@app.route('/<lang_code>/index')
def index():
    return render_template('url_processors/index_{}.html'.format(g.lang_code))


@app.route('/<lang_code>/about')
def about():
    return render_template('url_processors/about_{}.html'.format(g.lang_code))


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


url_value_processor(f)在请求匹配url后立即执行,先于before_request()方法执行。它可以修改url传递给视图方法的参数,该方法只是传值作用,return会被忽略。同时它可以传递参数给视图方法,所以在视图方法不用再写参数接收,这很有用,可以大大优化代码。1中代码则必须是 index(lang_code) 和 about(lang_code)。

@app.url_defaults
def url_default_pro(endpoint, values):
    values['lang_code'] = g.lang_code


url_defaults(f)可以自动将values的值注入到url_for中:

在页面中 url_for('about'),将得到about的访问地址,其中lang_code不指定将会错误,通过上面代码url_defaults可以自定注入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():
    ...


is_endpoint_expecting方法将迭代所以url规则,查询视图端点是否需要lang_code参数。


结合蓝图使用,由于蓝图定义前缀url,那么请求地址必须带上前缀url。蓝图支持通配符。

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():
    ...

展开阅读全文

评论

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 心情