视图装饰器¶
Python有一个非常有趣的特性,叫做函数修饰器。这就为Web应用程序提供了一些非常好的功能。因为flask中的每个视图都是一个函数,所以可以使用decorator向一个或多个函数注入额外的功能。这个 route()
装饰师是你可能已经用过的那个。但是有一些用例可以实现您自己的装饰器。例如,假设您有一个视图,该视图只能由登录的人使用。如果用户进入该站点但未登录,则应将其重定向到登录页面。这是一个很好的用例示例,其中装饰器是一个很好的解决方案。
需要登录的装饰器¶
所以让我们实现这样一个装饰器。decorator是包装和替换另一个函数的函数。由于替换了原始函数,因此需要记住将原始函数的信息复制到新函数。使用 functools.wraps()
为你处理这件事。
这个例子假设登录页面被称为``'login'并且当前用户存储在``g.user``中并且如果没有登录则是``None
。:
from functools import wraps
from flask import g, request, redirect, url_for
def login_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if g.user is None:
return redirect(url_for('login', next=request.url))
return f(*args, **kwargs)
return decorated_function
要使用装饰器,请将其作为最里面的装饰器应用于视图功能。 当应用更多装饰器时,请记住:meth:`~flask.Flask.route`装饰器是最外面的。:
@app.route('/secret_page')
@login_required
def secret_page():
pass
备注
这个 next
值将存在于 request.args
后一 GET
请求登录页面。你必须在发送 POST
从登录表单请求。您可以使用隐藏的输入标记执行此操作,然后从 request.form
当用户登录时。::
<input type="hidden" value="{{ request.args.get('next', '') }}"/>
缓存装饰器¶
假设您有一个执行昂贵计算的视图函数,因此您希望将生成的结果缓存一定时间。装饰师会很乐意的。我们假设您设置了一个缓存,如中所述 高速缓存 .
下面是一个缓存函数示例。它从特定前缀(实际上是格式字符串)和请求的当前路径生成缓存键。请注意,我们使用的函数首先创建装饰器,然后装饰函数。听起来糟透了?不幸的是,它有点复杂,但代码仍然应该是直接读取的。
然后,装饰功能将按以下方式工作
根据当前路径获取当前请求的唯一缓存密钥。
从缓存中获取该键的值。如果缓存返回了某些内容,我们将返回该值。
否则,将调用原始函数,并在提供的超时时间(默认为5分钟)将返回值存储在缓存中。
这里的代码:
from functools import wraps
from flask import request
def cached(timeout=5 * 60, key='view/{}'):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
cache_key = key.format(request.path)
rv = cache.get(cache_key)
if rv is not None:
return rv
rv = f(*args, **kwargs)
cache.set(cache_key, rv, timeout=timeout)
return rv
return decorated_function
return decorator
注意,这假定一个 cache
对象可用,请参见 高速缓存 .
模板装饰¶
不久前,TurboGears公司的人发明了一种常见的图案,那就是模板装饰。这个decorator的思想是返回一个字典,其中包含从view函数传递给模板的值,模板将自动呈现。有了这个,下面三个例子做得完全相同:
@app.route('/')
def index():
return render_template('index.html', value=42)
@app.route('/')
@templated('index.html')
def index():
return dict(value=42)
@app.route('/')
@templated()
def index():
return dict(value=42)
如您所见,如果没有提供模板名,它将使用URL映射的端点,并将点转换为斜线。+ '.html'
. 否则将使用提供的模板名称。当修饰函数返回时,返回的字典将传递给模板呈现函数。如果 None
如果返回的不是字典,则假定为空字典,如果返回的不是字典,则从函数中返回的字典不变。这样,您仍然可以使用重定向函数或返回简单字符串。
这是那个装饰师的代码:
from functools import wraps
from flask import request, render_template
def templated(template=None):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
template_name = template
if template_name is None:
template_name = f"{request.endpoint.replace('.', '/')}.html"
ctx = f(*args, **kwargs)
if ctx is None:
ctx = {}
elif not isinstance(ctx, dict):
return ctx
return render_template(template_name, **ctx)
return decorated_function
return decorator
终结点装饰器¶
当您想要使用werkzeug路由系统以获得更大的灵活性时,您需要将:class:`~werkzeug.routing.Rule`中定义的端点映射到视图函数。 这个装饰器可以做到这一点。 例如::
from flask import Flask
from werkzeug.routing import Rule
app = Flask(__name__)
app.url_map.add(Rule('/', endpoint='index'))
@app.endpoint('index')
def my_index():
return "Hello world"