视图装饰器

    让我们来实现这个装饰器。装饰器是一个包装并替换另一个函数的函数。既然源函数 已经被替代,就需要记住:要复制源函数的信息到新函数中。可以用 functools.wraps() 处理这个事情。

    下面是检查登录装饰器的例子。假设登录页面为 ,当前用户被储存在 g.user 中,如果还没有登录,其值为 None:

    为了使用这个装饰器呢,需要把这个装饰器放在最靠近函数的地方。当使用更进一步 的装饰器时,请记住要把 装饰器放在最外面:

    1. @app.route('/secret_page')
    2. @login_required
    3. def secret_page():
    4. pass

    Note

    登录页面在一个``GET`` 请求之后 next 值会存在于 request.args 之中。当从登录表单发送 POST 请求时必须一起传递它。可以使用一个 隐藏标记来做到这点,然后当用户登录时,从 request.form 获取它。

    下面是一个示例缓存函数。它根据一个特定的前缀(实际上是一个格式字符串) 和请求的当前路径生成缓存键。注意,我们先使用了一个函数来创建装饰器,这 个装饰器用于装饰函数。听起来拗口吧,确实有一点复杂,但是下面的示例代码 还是很容易读懂的。

    被装饰代码按如下步骤工作

    1. 基于当前路径获得当前请求的唯一缓存键。

    2. 从缓存中获取键值。如果获取成功则返回获取到的值。

    3. 否则调用原来的函数,并把返回值存放在缓存中,直至过期(缺省值为五分钟)。

    1. from functools import wraps
    2. from flask import request
    3. def decorator(f):
    4. def decorated_function(*args, **kwargs):
    5. cache_key = key.format(request.path)
    6. rv = cache.get(cache_key)
    7. if rv is not None:
    8. return rv
    9. rv = f(*args, **kwargs)
    10. cache.set(cache_key, rv, timeout=timeout)
    11. return rv
    12. return decorated_function
    13. return decorator

    注意,以上代码假设存在一个可用的实例化的 cache 对象,更多信息参见 缓存 方案。

    不久前, TurboGear 的人发明了模板装饰器这个通用模式。其工作原理是返回一个 字典,这个字典包含从视图传递给模板的值,模板自动被渲染。以下三个例子的功能 是相同的:

    正如你所见,如果没有提供模板名称,那么就会使用 URL 映射的端点(把点转换为 斜杠)加上 '.html' 。如果提供了,那么就会使用所提供的模板名称。当装饰 器函数返回时,返回的字典就被传送到模板渲染函数。如果返回的是 None ,就 会使用空字典。如果返回的不是字典,那么就会直接传递原封不动的返回值。这样就 可以仍然使用重定向函数或返回简单的字符串。

    以下是装饰器的代码:

    1. from functools import wraps
    2. def templated(template=None):
    3. def decorator(f):
    4. @wraps(f)
    5. def decorated_function(*args, **kwargs):
    6. template_name = template
    7. if template_name is None:
    8. template_name = f"{request.endpoint.replace('.', '/')}.html"
    9. ctx = f(*args, **kwargs)
    10. if ctx is None:
    11. ctx = {}
    12. elif not isinstance(ctx, dict):
    13. return ctx
    14. return render_template(template_name, **ctx)

    当你想要使用 werkzeug 路由系统,以便于获得更强的灵活性时,需要和 中定义的一样,把端点映射到视图函数。这样就 需要用的装饰器了。例如: