让我们先来看一个简单的例子,假设有下面这样一个蓝图(是关于用户主页的):
from flask import Blueprint, render_template profile = Blueprint('profile', __name__) @profile.route('/<user_url_slug>') def timeline(user_url_slug): # Do some stuff return render_template('profile/timeline.html') @profile.route('/<user_url_slug>/photos') def photos(user_url_slug): # Do some stuff return render_template('profile/photos.html') @profile.route('/<user_url_slug>/about') def about(user_url_slug): # Do some stuff return render_template('profile/about.html')
从上面我们可以看出,所有的路由都是以user_url_slug
开头的,若这样写代码的话,会增加代码的复杂性、降低可维护性。为了解决这个问题,我们可以在蓝图中定义动态的URL前缀。让我们把蓝图定义改成这样:
profile = Blueprint('profile', __name__, url_prefix='/<user_url_slug>')
或者在注册到app时指定:
app.register_blueprint(profile, url_prefix='/<user_url_slug>')
现在,我们可以把路由写成下面的精简形式:
@profile.url_value_preprocessor def pull_user_url_slug(endpoint, values): g.user_url_slug = values.pop('user_url_slug') query = User.query.filter_by(url_slug=g.user_url_slug) g.profile_owner = query.first_or_404() @profile.route('/') def timeline(): return render_template('profile/timeline.html') @profile.route('/photos') def photos(): return render_template('profile/photos.html') @profile.route('/about') def about(): return render_template('profile/about.html')
url_value_preprocessor
装饰器用于把user_url_slug
值弹出,并保存到g
变量中,这样就不会传递给路由函数。
实际应用中,我们会发现,若使用url_for
来生成URL,会出现参数不足的错误,这是为什么呢?这是因为我们把user_url_slug
弹出了,url_for
工作时需要使用这个值,但是这个时候这个值找不到了,因此我们要把user_url_slug
值重新压入:
profile.url_defaults def add_user_url_slug(endpoint, values): values.setdefault('user_url_slug', g.user_url_slug)
完整例子:
from flask import Blueprint, render_template profile = Blueprint('profile', __name__, url_prefix='/<user_url_slug>') @profile.url_defaults def add_user_url_slug(endpoint, values): values.setdefault('user_url_slug', g.user_url_slug) @profile.url_value_preprocessor def pull_user_url_slug(endpoint, values): g.user_url_slug = values.pop('user_url_slug') query = User.query.filter_by(url_slug=g.user_url_slug) g.profile_owner = query.first_or_404() @profile.route('/') def timeline(): return render_template('profile/timeline.html') @profile.route('/photos') def photos(): return render_template('profile/photos.html') @profile.route('/about') def about(): return render_template('profile/about.html')