Flask - 模板引擎

flask-script

  • 说明:flask 终端启动的参数解析器,只需要通过启动传递不同的参数即可完成不同方式的启动
  • 安装:pip install flask-script
  • 使用:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    from flask import Flask
    from flask_script import Manager


    app = Flask(__name__)
    # 创建对象
    manager = Manager(app)

    @app.route('/')
    def index():
    return 'Hello Flask'

    if __name__=="__main__":
    # app.run(debug=True)
    manager.run()

    启动:python manager.py runserver

  • 启动参数
    1
    2
    3
    4
    5
    6
    -? 或 --help     # 查看使用帮助
    -h 或 --host # 指定主机
    -p 或 --port # 指定端口
    --threaded # 开启多线程
    -d # 开启调试模式
    -r # 重新加载

    启动示例:python manager.py runserver -d -r

蓝本 (blueprint)

  • 说明:当项目越来越复杂时,所有的视图函数都放在一个文件中,很明显是不合适的;如果能够根据功能需求划分到不同的文件中就好了,幸好有蓝本的存在,专门用于解决此问题。

  • 使用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from flask import Blueprint

    # 创建蓝本对象
    user = Blueprint('user', __name__, url_prefix='/user')


    # 添加路由
    @user.route('/login/')
    def login():
    return '欢迎登录'
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    from flask import Flask
    from flask_script import Manager

    app = Flask(__name__)
    # 创建对象
    manager = Manager(app)


    @app.route('/')
    def index():
    return 'Hello Flask'


    # 注册蓝本,可以指定路由前缀,创建时也可以指定,但注册时优先级高
    from user import user

    app.register_blueprint(user, url_prefix='/u')

    if __name__ == "__main__":
    # app.run(debug=True)
    manager.run()

模板引擎

  • 说明:
    • 模板文件是按照特定语法规则书写的专门负责显示特定效果的文件;
    • 模板引擎就是负责特定语法规则的解析和替换的工具。
  • Jinja2:
    • flask 中使用的是 Jinja2 的模板引擎,它是 flask 核心开发者人员开发的。

Jinja2 使用流程

  • 创建工程,准备目录

    1
    2
    3
    project/			# 工程目录
    manage.py # 启动控制文件
    templates/ # 模板文件目录
  • 准备模板文件

    • 在 templates 下创建一个 hello.html 模板文件,内容如下

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8">
      <title>模板引擎测试</title>
      </head>
      <body>
      <h1>Hello Flask</h1>
      </body>
      </html>
  • 模板渲染:需要使用专门的渲染函数

    1. 渲染模板文件:render_template
    2. 渲染模板字符串:render_template_string
  • 开启自动加载模板文件

    1
    2
    # 模板文件修改后自动加载
    app.config['TEMPLATES_AUTO_RELOAD'] = True
  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    from flask import Flask, render_template, render_template_string
    from flask_script import Manager

    app = Flask(__name__)
    manager = Manager(app)

    # 模板文件修改后自动加载
    app.config['TEMPLATES_AUTO_RELOAD'] = True


    @app.route('/')
    def index():
    # return '<h1>Flask-template</h1>'
    # 渲染模板文件
    # return render_template('hello.html')
    # 渲染模板字符串
    return render_template_string('<h1>渲染模板字符串</h1>')


    if __name__ == '__main__':
    manager.run()

使用变量

  • 模板文件中:

    1
    {{ 变量名 }}
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>变量</title>
    </head>
    <body>
    <h1>Hello {{ name }}!</h1>
    <h1>Hello {{ g.name }}!</h1>
    </body>
    </html>
  • 渲染时:render_template('模板文件名', 变量名=变量值)

    1
    2
    3
    4
    5
    @app.route('/var/')
    def var():
    # 可以在模板中直接使用,渲染时不需要分配
    g.name = 'curry'
    return render_template('var.html', name='ergouzi')
  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    from flask import Flask, render_template, render_template_string, g
    from flask_script import Manager

    app = Flask(__name__)
    manager = Manager(app)

    # 模板文件修改后自动加载
    app.config['TEMPLATES_AUTO_RELOAD'] = True


    @app.route('/')
    def index():
    # return '<h1>Flask-template</h1>'
    # 渲染模板文件
    # return render_template('hello.html')
    # 渲染模板字符串
    return render_template_string('<h1>渲染模板字符串</h1>')


    @app.route('/var/')
    def var():
    # 可以在模板中直接使用,渲染时不需要分配
    g.name = 'curry'
    return render_template('var.html', name='ergou')


    if __name__ == '__main__':
    manager.run()

使用函数

  • 模板文件中渲染变量时:

    1
    {{ 变量名 | 函数名 }}
  • 示例:

    1
    <h1>Hello {{ name | upper }}!</h1>
  • 常用函数:

    函数 说明
    upper 全部大写
    lower 全部小写
    title 每个单词首字母大写
    capitalize 首字母大写
    trim 去掉两遍空白
    striptags 过滤 HTML 标签
    safe 渲染时不转义,默认转义

    safe 不要乱用,只能用在足够信任的变量渲染中

流程控制

  • 分支结构(if-else)

    1
    2
    3
    4
    5
    {% if name %}
    <h1>Hello {{ name }}!</h1>
    {% else %}
    <h1>Hello World!</h1>
    {% endif %}
  • 循环结构(for-in)

    1
    2
    3
    4
    5
    <ol>
    {% for i in range(1, 11) %}
    <li>{{ i }}</li>
    {% endfor %}
    </ol>
  • 说明:

    1
    将控制语句写在{%  %}中
  • 注释:

    1
    写在{#  #}中

文件包含

  • 说明:就是原封不动的将另一个文件中的内容加载过来,避免了重新书写工作。
  • 使用:
    1
    2
    # {% include '被包含模板文件名' %}
    {% include 'include2.html' %}

宏的使用

  • 需要先定义在使用
  • 格式:
    • 定义宏
      1
      2
      3
      {% macro 宏名(参数) %}
      宏的内容
      {% endmacro %}
    • 调用宏
      1
      {{ 宏名(参数) }}
  • 示例:
    1
    2
    3
    4
    5
    6
    7
    {# 定义宏 #}
    {% macro show_name(name) %}
    <h1>Hello {{ name }}!</h1>
    {% endmacro %}

    {# 调用宏 #}
    {{ show_name(name) }}
  • 导入宏:
    1
    2
    3
    4
    5
    6
    7
    {% from '文件名' import 宏名 %}

    {# 导入宏 #}
    {% from 'macro.html' import show_name %}

    {# 调用宏 #}
    {{ show_name(name) }}
  • 说明:宏的使用采用与 python 中函数一样的方式进行定义和调用。

模板继承

  • 基础模板,用来被继承
  • 子模板,继承自基础模板
    1
    {% extends '基础模板' %}
  • 块标识:
    1
    {% block 块名 %}{% endblock %}
  • 块重写:在子模板中,可以通过同名 block 的书写对继承的内容进行重写或删除
  • 保留基础模板内容:
    1
    {{ super() }}
  • 说明:在模板继承使用过程中,若重写了一个 block 后发现完全错了,很可能是没有使用
    1
    {{ super() }}
  • 示例:
    • 基础模板
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8">
      <title>{% block title %}父级模板标题{% endblock %}</title>
      </head>
      <body>
      {% block body %}
      默认内容
      {% endblock %}
      </body>
      </html>
    • 子模板
      1
      2
      3
      4
      5
      6
      7
      8
      9
      {# 继承自父级模板 #}
      {% extends 'parent.html' %}

      {% block title %}欢迎登录{% endblock %}
      {% block body %}
      {# 保留继承的内容 #}
      {{ super() }}
      欢迎你的到来。。。
      {% endblock %}

flask-bootstrap

  • 安装:pip install flask-bootstrap
  • 初始化:
    1
    2
    3
    4
    5
    from flask_bootstrap import Bootstrap
    bootstrap = Bootstrap(app)
    # 若创建时app不存在,可以先创建再初始化
    # bootstrap = Bootstrap()
    # bootstrap.init_app(app)
  • 模板继承
    1
    2
    {# 继承自bootstrap的基础模板 #}
    {% extends 'bootstrap/base.html' %}
  • 说明:通过重写基础模板定义的 block 即可完成特定效果的展示
  • bootstrap 基础模板中提供的 block
    block 说明
    doc 整个 HTML 文档
    html 整个 HTML 标签
    head head 标签
    title title 标签
    styles 引入 CSS 样式
    metas 一组 meta 标签
    body body 标签
    navbar 用户自定义的导航条
    content 用户自定义内容
    script 引入 JS 文件

    使用 bootstrap 时,若重写了一个 block,原来的显示效果消失,八成是因为忘记了 super。

定制项目基础模板

  • 说明:在很多网站中,绝大多数页面长得几乎一模一样,只有个别区域的差别;若每个页面都单独定制势必会出现大量的重复代码,为了解决此类问题,最好定制一个基础,将大致的内容全部写好,并且全部起好名字,然后让其他页面继承自该基础模板,简单修改即可达到想要的效果。
  • 步骤:
    • 从 bootstrap 官网复制一个顺眼的导航条
    • 显示反色导航条:navbar-inverse
    • 修改容器布局:container-fluid => container
    • 定制圆角:style="border-radius: 0"
    • 根据需要定制导航条上的内容
    • 修改折叠内容的定位方式 id => calss
  • 基础模板示例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    {% extends 'bootstrap/base.html' %}

    {% block title %}默认标题{% endblock %}

    {% block navbar %}
    <nav class="navbar navbar-inverse" style="border-radius: 0">
    <div class="container">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="navbar-header">
    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
    data-target=".navbar-collapse" aria-expanded="false">
    <span class="sr-only">Toggle navigation</span>
    <span class="icon-bar"></span>
    <span class="icon-bar"></span>
    <span class="icon-bar"></span>
    </button>
    <a class="navbar-brand" href="#">首页</a>
    </div>

    <!-- Collect the nav links, forms, and other content for toggling -->
    <div class="collapse navbar-collapse">
    <ul class="nav navbar-nav">
    <li><a href="#">版块一</a></li>
    <li><a href="#">版块二</a></li>
    <li><a href="#">板块三</a></li>
    </ul>
    <ul class="nav navbar-nav navbar-right">
    <li><a href="#">登录</a></li>
    <li><a href="#">注册</a></li>
    </ul>
    </div><!-- /.navbar-collapse -->
    </div><!-- /.container -->
    </nav>
    {% endblock %}

    {% block content %}
    <div class="container">
    {% block page_content %}
    默认内容
    {% endblock %}
    </div>
    {% endblock %}

练习

1
2
1.定制登录页面、注册页面、404页面
2.试着完成静态文件的加载