Flask模板全局变量以及自定义过滤器

2021-09-22 14:01:16 785

简介

Flask是一个微框架,但是麻雀虽小,五脏俱全。在实现基本的web功能的同时,Flask还提供了很多Api供我们开发者自定义一些功能,比如很多已Flask开头的第三方扩展,本文主要介绍如何通过一些Api来实现一些比较不常用的功能。

1. 模板全局变量

1.1 current_user

使用过Flask-Login的同学应该都知道,在他的扩展中有一个属性current_user用来保存当前登录用户的相关信息,比如登录状态、登录信息等。而且这个current_user属性除了能在我们后端的python代码中使用外,还可以在任何模板中进行使用,如下面的代码片段

在python后端代码中使用

def test():
    ...
    # 在python后端代码中使用    
    if current_user.is_authenticated:
        li = LoveInfo(user=current_user.username, user_ip=remote_ip)
    else:
        li = LoveInfo(user='Anonymous', user_ip=remote_ip)

在html模板文件中使用

{% if not current_user.is_authenticated %}
<ul class="navbar-nav f-17">
    <li class="nav-item"><a class="nav-link nav-text" href="/auth/login/">登录</a></li>
    <li class="nav-item"><a class="nav-link nav-text" href="/auth/register/">注册</a></li>
</ul>
{% else %}
    ...
{% endif %}

在python代码中还比较好理解,当我们需要使用的时候,直接通过import导入即可,但是为什么current_user能够在任意模板文件中使用呢?我们可以通过分析Flask-Login的源码来理解为何可以在任意模板文件中使用。一般的,当我们使用Flask-Login的时候都是通过实例化LoginManager示例,然后通过instance.init_app(app, *args)来注册实例。我们可以进入LoginManager源码,init_app()函数代码如下

def init_app(self, app, add_context_processor=True):
    '''
    Configures an application. This registers an `after_request` call, and
    attaches this `LoginManager` to it as `app.login_manager`.

    :param app: The :class:`flask.Flask` object to configure.
    :type app: :class:`flask.Flask`
    :param add_context_processor: Whether to add a context processor to
        the app that adds a `current_user` variable to the template.
        Defaults to ``True``.
    :type add_context_processor: bool
    '''
    app.login_manager = self
    app.after_request(self._update_remember_cookie)

    if add_context_processor:
        app.context_processor(_user_context_processor)

可以看到add_context_processor变量的注释

Whether to add a context processor to the app that adds a `current_user` variable to the template. Defaults to ``True``.

 翻译为中文的大概意思就是,是否向应用程序添加上下文处理器,以将 current_user 变量添加到模板,默认为True。继续看if语句里面的代码,_user_context_processor是一个方法,其代码如下

def _user_context_processor():
    return dict(current_user=_get_user())

可以看到函数就是返回了一个字典对象,可以发现字典的键就是current_user。为什么current_user可以使用在任意模板中,就是通过app.context_processor Api添加了一个应用程序上下文函数来实现,在Flask的文档中描述如下图所示,翻译过来的意思就是注册一个模板上下文处理器函数。

1.2 使用

context_processor的使用方法有两种,如下代码所示,分别使用装饰器的方式定义模板全局变量以及方法,已函数的形式定义模板全局变量。

from flask import Flask
import datetime

app = Flask(__name__)


# use decorator
@app.context_processor()
def cur_day():
    return datetime.date.today()


# context function 
@app.context_processor()
def get_uuid():
    import uuid

    def _uuid():
        return uuid.uuid3()

    return dict(uuid=_uuid)


def current_time():
    return dict(current_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))


# use context_processor function
app.context_processor(current_time)

2.自定义过滤器

Flask已经内置了很多过滤器,比如truncatelength等,除了内置的过滤器之外,我们还可以自定义Jinja2模板的过滤器。在Flask中有两种方法自定义过滤器,代码如下

@app.template_filter('reverse')
def reverse_filter(s):
    return s[::-1]

def reverse_filter(s):
    return s[::-1]
app.jinja_env.filters['reverse'] = reverse_filter

第一种方法是使用app.template_filter()装饰器来实现,装饰器中的参数,就是后续可以在Jinja2模板文件中使用的过滤器名称;

第二种方法是通过app.jinja_env.filters将过滤器函数存入字典中,字典的键就是Jinja2模板文件中使用的过滤器名称;

示例代码链接: