下载工作台
Flask Web 开发

Jinja2 模板与静态资源

试读上半部分 · 解锁后可读全文

第 3 章 · Jinja2 模板与静态资源

本章目标:在 api-demo 的 admin 蓝图中使用 Jinja2 渲染 HTML 管理页;掌握 extends / block 模板继承与 macro 复用片段;正确配置 url_for('static', ...) 引用 CSS/JS;使用 flashget_flashed_messages 展示操作反馈;理解 Flask 模板目录约定并与 Django 模板对照。

学时建议:4~5 小时(含 2 小时跟练)

前置:完成 flask-web ch01~ch02(蓝图、url_for、admin 蓝图占位)。


3.1 场景说明:轻量管理页

api-demo 以 API 为主,但运营仍需浏览器管理页维护商品(完整 CRUD 在 ch04~ch05)。与 shop-demo 的 Django Admin 不同,这里用自定义模板打造极简后台。

页面路径模板说明
仪表盘/admin/admin/dashboard.html统计卡片
商品列表/admin/products/admin/product_list.html表格 + flash
布局基类base.html导航、静态资源

虚构对外 API 文档仍指向 https://api.example.com;管理页仅本地 http://127.0.0.1:5000/admin/ 访问。


3.2 模板与静态目录结构

Flask 默认从应用根下的 templates/static/ 加载。

api-demo/
├── api_demo/
│   ├── templates/
│   │   ├── base.html
│   │   ├── partials/
│   │   │   └── flash.html
│   │   ├── macros/
│   │   │   └── ui.html
│   │   └── admin/
│   │       ├── dashboard.html
│   │       └── product_list.html
│   ├── static/
│   │   ├── css/admin.css
│   │   └── js/admin.js
│   └── routes/admin.py
资源类型目录引用方式
HTML 模板templates/render_template("admin/dashboard.html")
CSS/JS/图片static/url_for('static', filename='css/admin.css')

创建应用时指定(可选,默认已正确):

app = Flask(__name__, template_folder="templates", static_folder="static")

3.3 基模板 base.html

api_demo/templates/base.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>{% block title %}api-demo 管理{% endblock %}</title>
  <link rel="stylesheet" href="{{ url_for('static', filename='css/admin.css') }}">
</head>
<body>
  <header class="topbar"><strong>api-demo</strong></header>
  <nav class="sidebar">
    <a href="{{ url_for('admin.dashboard') }}">仪表盘</a>
    <a href="{{ url_for('admin.product_list') }}">商品</a>
    <a href="{{ url_for('api.product_list') }}">API 预览</a>
  </nav>
  <main class="content">
    {% include "partials/flash.html" %}
    {% block content %}{% endblock %}
  </main>
  <script src="{{ url_for('static', filename='js/admin.js') }}"></script>
</body>
</html>

api_demo/templates/partials/flash.html

{% with messages = get_flashed_messages(with_categories=true) %}
  {% if messages %}
    <ul class="flash-list">
      {% for category, message in messages %}
        <li class="flash flash-{{ category }}">{{ message }}</li>
      {% endfor %}
    </ul>
  {% endif %}
{% endwith %}

3.4 extends 与 block 继承

子模板通过 extends 填充父模板的 block

api_demo/templates/admin/dashboard.html

{% extends "base.html" %}

{% block title %}仪表盘 · api-demo{% endblock %}

{% block content %}
  <h1>仪表盘</h1>
  <div class="cards">
    <div class="card">
      <h3>商品数</h3>
      <p>{{ product_count }}</p>
    </div>
    <div class="card">
      <h3>API 基址</h3>
      <p><code>{{ api_base }}</code></p>
    </div>
  </div>
{% endblock %}

api_demo/templates/admin/product_list.html

{% extends "base.html" %}

{% block title %}商品列表 · api-demo{% endblock %}

{% block content %}
  <h1>商品列表</h1>
  <p><a class="btn" href="{{ url_for('admin.product_create') }}">新建商品</a></p>
  <table class="table">
    <thead>
      <tr><th>ID</th><th>名称</th><th>价格</th><th>库存</th></tr>
    </thead>
    <tbody>
      {% for p in products %}
      <tr>
        <td>{{ p.id }}</td>
        <td>{{ p.name }}</td>
        <td>¥{{ "%.2f"|format(p.price) }}</td>
        <td>{{ p.stock }}</td>
      </tr>
      {% else %}
      <tr><td colspan="4">暂无商品</td></tr>
      {% endfor %}
    </tbody>
  </table>
{% endblock %}
Jinja2Django 模板说明
{% extends %}{% extends %}相同
{% block %}{% block %}相同
{% for %}...{% else %}{% empty %}Flask 用 else 分支
format 过滤器(如 "%.2f" 格式化价格)过滤器Jinja2 用竖线调用过滤器

3.5 macro 宏复用

api_demo/templates/macros/ui.html

{% macro badge(text, kind="default") %}
  <span class="badge badge-{{ kind }}">{{ text }}</span>
{% endmacro %}

{% macro page_header(title, subtitle="") %}
  <header class="page-header">
    <h1>{{ title }}</h1>
    {% if subtitle %}<p class="muted">{{ subtitle }}</p>{% endif %}
  </header>
{% endmacro %}

在列表页引用:

以下内容需解锁后阅读

试读已结束。解锁本章 ¥5.00,或开通年度会员畅读全部教程。
年度会员 ¥199.00/年; 小紫 AI 工作台有效会员 ¥99.00/年

正文仅在服务端鉴权后下发,未付费无法获取下半部分内容。