模板

Flask 使用 Jinja2 作为模板引擎生成 HTML。模板把页面结构与 Python 逻辑分离,并默认对变量做 HTML 转义,天然防御 XSS。

基本用法

from flask import render_template

@app.get("/")
def index():
    return render_template("index.html", name="Alice", items=["a", "b"])

render_template 从应用(或蓝图)的 templates/ 目录查找模板,关键字参数成为模板中的变量。

模板语法

<!-- 变量输出(自动 HTML 转义) -->
<p>{{ name }}</p>

<!-- 属性/下标访问 -->
<p>{{ user.email }} / {{ row["title"] }}</p>

<!-- 条件 -->
{% if user %}
  <p>欢迎,{{ user.name }}</p>
{% else %}
  <a href="{{ url_for('auth.login') }}">登录</a>
{% endif %}

<!-- 循环 -->
<ul>
  {% for item in items %}
    <li>{{ loop.index }}. {{ item }}</li>
  {% else %}
    <li>暂无数据</li>
  {% endfor %}
</ul>

<!-- 过滤器 -->
{{ name|upper }} {{ content|truncate(100) }} {{ price|round(2) }}

loop 对象提供 index(从 1 起)、firstlast 等循环状态。

模板继承

用基础模板定义骨架,子模板只填充差异部分:

<!-- templates/base.html -->
<!doctype html>
<html>
<head>
  <title>{% block title %}Site{% endblock %}</title>
  <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
  <nav>…</nav>
  <main>{% block content %}{% endblock %}</main>
</body>
</html>
<!-- templates/index.html -->
{% extends "base.html" %}
{% block title %}首页{% endblock %}
{% block content %}
  <h1>Hello, {{ name }}!</h1>
{% endblock %}

复用片段:include 与宏

{% include "partials/flash.html" %}

{% macro field(label, name, type="text") %}
  <label>{{ label }} <input type="{{ type }}" name="{{ name }}"></label>
{% endmacro %}

{{ field("邮箱", "email", type="email") }}

模板中可直接使用的对象

Flask 自动注入:requestsessiongurl_for()get_flashed_messages()config

<a href="{{ url_for('index') }}" {% if request.path == '/' %}class="active"{% endif %}>首页</a>

自定义过滤器与全局变量

@app.template_filter("datefmt")
def datefmt(value, fmt="%Y-%m-%d"):
    return value.strftime(fmt)

@app.context_processor
def inject_globals():
    return {"site_name": "垦荒学园"}    # 所有模板可用 {{ site_name }}

转义与安全

  • 变量默认转义;确认安全的 HTML 用 {{ content|safe }} 输出,但绝不要对用户输入使用 safe
  • Python 端可用 markupsafe.Markup 标记安全字符串。

静态文件(CSS/JS/图片)的组织在下一章介绍。