12.7 Web开发——Flask示例讲解¶
内容梗概¶
本课通过示例代码完整讲解 Flask 中 Jinja2 模板的使用,把博客作业从"返回字符串"升级为"渲染真正的 HTML 页面"。内容包括:render_template 函数与 templates 文件夹约定、模板变量传参(key=value)、Jinja2 模板语言的三类语法(表达式、注释、控制语句)、if 条件渲染、for 循环渲染列表(配合读取 txt 文件模拟数据库),以及**模板继承**(layout.html + {% extends %} + {% block %})实现全站统一布局。最后明确了博客作业的要求与评分原则。
知识点详解¶
render_template 与 templates 文件夹(约 00:00–06:00)¶
- 打开示例仓库第二个文件夹(Jinja2 templates 示例,
01目录内有app.py和templates文件夹)。 templates文件夹的名字是 Flask 默认的,不能改(改了要做特殊配置,本课不讲);模板文件名(如index.html)可以随意改,只要代码里跟着改。- 之前 endpoint 直接返回字符串;要返回真正的 HTML,需从 flask 库多导入一个函数:
在 endpoint 中写
return render_template('index.html')——"渲染模板"。Flask 会自动到内置约定的templates文件夹里找对应文件(写abc.html就要有abc.html)。 - 模板文件大体是符合 HTML 格式的内容,但其中有双花括号括起来的"奇怪"内容——这就是 Jinja2 模板语言。
Jinja2 模板语言基础:变量与表达式(约 06:00–13:20)¶
- Jinja2 包含两部分:模板语言(写在 HTML 里)和**模板引擎**(调用
render_template时按规则自动替换模板中的内容)。 {{ }}(双花括号)里写**表达式**:可以是单个变量、加减乘除等 Python 运算,甚至 Python 函数。- 后端给模板变量赋值的方法——给
render_template加 key=value 形式的新参数: 前面的 key 是模板中用的变量名(两边要一致),后面的 value 是后端算出来的变量或值。渲染时模板里的{{ now }}被替换成该字符串。 - 时间获取:
datetime包里的datetime对象有now()方法返回当前系统时间,再用格式化方法转成字符串。 - 效果:每次刷新页面时间都会变——这就是动态网页。完全可以复杂化:比如从数据库读库存,刷新时页面动态变化(但仍不如 Ajax 那样不用刷新)。
控制语句:if 与 for(约 13:25–24:10)¶
- 三类语法速记:
{{ ... }}:表达式(变量、运算、函数){# ... #}:注释{% ... %}:控制语句(if / else / for 等),结束要有{% endif %}/{% endfor %};语法与 Python 自身不同,属于 Jinja2 模板语言。- if 示例:后端传
goods=999,模板中: 999 显示"大家抢购了";改成大于 1000 的值刷新就显示"货物充足"。前端模板一行没改,只是后端数据变了页面就变——后端完全可以接数据库读这个数(老师始终刻意回避数据库,因为还没学)。 - for 示例:把示例里的
students.txt复制进来,后端读文件模拟数据库:模板中: 用无序列表f = open('students.txt', encoding='utf-8') # 读文本模式默认 'rt';注意指定 encoding students = f.readlines() # 返回列表,每个元素是文件中的一行(字符串) return render_template('index.html', students=students)ul/li把几十个学生名字从上到下显示出来。(细节:行尾换行符需自行去掉,与本课关系不大不赘述。) - for 循环的优势:几百条数据不用写几百行 HTML,一循环就搞定——这是模板语言最有优势的地方。
模板继承(约 24:10–41:20)¶
- 动机:一个网站的整体布局永远不变——logo、标题、导航栏、底部备案/友情链接,变的只是中间内容。若博客有四个页面,每个模板都要写一遍头和尾,很浪费。解决办法:模板继承(类似引用头文件的逻辑)。
- 做法(参考示例仓库中使用 JS 的那个例子,
templates里有首页、登录、水印三个页面外加一个layout.html): layout.html(布局文件):写完整的 HTML 结构(head、body、引入 CSS/JS),中间用{% block content %}...{% endblock %}划出**可变化的块**(block 是关键词,content 是起的名字)。- 子页面(如
index.html)第一行写: 告诉 Jinja2 引擎本页面基于 layout 扩展;然后逐个重写 block,把{% block pagename %}、{% block content %}等块的内容替换成自己的。 - 动手实践(回到自己的 blog 项目):
- 新建
templates文件夹,新建layout.html:写入基本结构,标题"我的博客",导航栏三个链接——首页对应/、文章对应/posts、关于对应/about(正好对应 12.5 定义的三个路由);定义两个块:title(默认"首页")和content(默认空)。 index.html:首行{% extends "layout.html" %},重写两个块;块内不需要完整 HTML 结构,只写局部 HTML 元素。- endpoint 改为
render_template('index.html')(渲染具体页面,而不是直接渲染布局文件)。 posts.html照葫芦画瓢:改成文章列表(链接指向如/post1),再用 for 循环读取 txt 的能力留给大家自己练。- 踩坑演示:点击"文章一号"链接显示 Not Found——因为
/post1这个路径没有定义对应的路由函数,需要自己处理。
示例与演示(作业要求与解题思路)¶
- 作业:用 Flask 做一个博客网站,要求:
- 多个页面:首页、文章列表(posts)、关于我(about)等,各页面对应各自的 endpoint 和模板;
- 使用模板继承(layout + extends + block)保持全站统一风格;
- 必须用虚拟环境(pipenv)安装 Flask,老师会检查;
- 可扩展方向(加分项,非必须):引入 CSS/JS 美化页面;在某个路径下放一堆 txt 当文章,循环读取加载、每篇作为一个页面;愿意的话也可以接数据库(可能比较费劲)。
- 评分说明:归一化给分——做得最好的给 100 分,其他人折合,分数不会太低;主要看**程序结构能否正常运行、变量命名是否规范、提交是否及时**,不考 JS/CSS 精美度。
- 老师**不会发示例代码**(发了等于白给,人人相似度 100%),已做好一键查重脚本——不要抄;可以看回放学习。
重点与难点¶
templates文件夹名是约定,不能乱改;模板文件名随意。render_template传参:key 必须与模板里的变量名一致。- Jinja2 三种定界符不要混:
{{ }}表达式、{# #}注释、{% %}控制语句;控制语句必须有endif/endfor收尾,这是与 Python 缩进语法不同的易错点。 - 读文件记得
encoding='utf-8',否则默认编码可能出错;readlines()读出的每行带换行符。 - 子模板首行必须是
{% extends %};块内只写局部 HTML,不要写完整文档结构。 - 导航链接指向的路径必须有对应路由,否则 404——页面链接和路由表要配套设计。
- debug 模式下改代码自动重载;没开 debug 要 Ctrl+C 重启(老师课上自己就踩了)。
关联内容¶
- 本课是第 12 章的集大成:12.5 的路由(endpoint)、12.6 的 MVC(本课讲的就是 View 部分 + Controller 配合)在本课合流为完整博客。
- 模板继承中导航栏三个链接直接对应 12.5 定义的三条路由(
/、/posts、/about)。 - 读 txt 模拟数据库呼应 12.3 动态示例的
students.txt和 12.4 全景图中"txt 换成数据库"的说法;数据库本身留给单独课程。 - 虚拟环境要求回扣第 10 章(pipenv);
datetime、文件读写(open/readlines/encoding)回扣前面章节的基础语法。