文章目录
- [摘要,视图函数只负责请求 → 响应,业务逻辑(数据处理)和表现逻辑(HTML 页面生成)要分开,模板(Jinja2) 用来渲染页面 → 表现逻辑移到模板中](#摘要,视图函数只负责请求 → 响应,业务逻辑(数据处理)和表现逻辑(HTML 页面生成)要分开,模板(Jinja2) 用来渲染页面 → 表现逻辑移到模板中)
-
- [什么是业务逻辑 vs 表现逻辑](#什么是业务逻辑 vs 表现逻辑)
- 为什么要用模板【带占位符的文件】(Template)?
- 渲染(Rendering)是什么?把模板里的占位符替换成真实值
- [3.1 Jinja2模板引擎](#3.1 Jinja2模板引擎)
-
- 渲染模板
-
- [默认情况下,Flask在应用目录中的templates子目录里寻找模板。应用目录是哪个?创建 Flask 对象的那个 Python 文件所在目录](#默认情况下,Flask在应用目录中的templates子目录里寻找模板。应用目录是哪个?创建 Flask 对象的那个 Python 文件所在目录)
- [render_template() 把模板和数据结合,并渲染成最终的html,返给浏览器](#render_template() 把模板和数据结合,并渲染成最终的html,返给浏览器)
- [3.1.2 变量](#3.1.2 变量)
-
-
A value from a dictionary: {{ mydict['key'] }}.
-
A value from a list: {{ mylist[3] }}.
-
A value from a list, with a variable index: {{ mylist[myintvar], mydict[mykey] }}.
-
A value from an object's method: {{ myobj.somemethod() }}.
-
[可以在模板里几乎和 Python 一样操作数据,](#可以在模板里几乎和 Python 一样操作数据,)
-
[过滤器 把左边的值传给右边的过滤器](#过滤器 把左边的值传给右边的过滤器)
-
- [safe:渲染时不转义 HTML](#safe:渲染时不转义 HTML)
- capitalize:首字母大写,其他小写
- lower:全部小写
- upper:全部大写
- title:每个单词首字母大写
- trim:去掉首尾空格
- [striptags:去掉 HTML 标签](#striptags:去掉 HTML 标签)
- 链式调用:组合多个过滤器
-
- 3.1.3 控制结构
-
- 条件判断(if/else)
- 循环(for)
- [宏(macro) --- 模板里的"函数"](#宏(macro) — 模板里的“函数”)
-
- 宏的导入(import)
-
- [Jinja2 宏导入从 Flask 的模板根目录 (templates) 开始找,相对路径写文件名或子目录路径即可。](#Jinja2 宏导入从 Flask 的模板根目录 (templates) 开始找,相对路径写文件名或子目录路径即可。)
- [include --- 引入模板片段。直接把另一个模板内容原封不动插入。](#include — 引入模板片段。直接把另一个模板内容原封不动插入。)
-
- [从 Flask 的模板根目录开始找(默认模板根目录)](#从 Flask 的模板根目录开始找(默认模板根目录))
- [include ------ 引入模板片段, import ------ 引入宏(宏是函数)](#include —— 引入模板片段, import —— 引入宏(宏是函数))
- [模板继承(extends / block / super)](#模板继承(extends / block / super))
- [Jinja2 的重复使用代码片段方法总结,宏,include,模板继承](#Jinja2 的重复使用代码片段方法总结,宏,include,模板继承)
- [3.2 使用Flask-Bootstrap集成Bootstrap](#3.2 使用Flask-Bootstrap集成Bootstrap)
-
- [Bootstrap 是什么?网页美化工具包](#Bootstrap 是什么?网页美化工具包)
- [Flask-Bootstrap 的作用:把bootstrp包装成jinja2可用的模板,从而实现模板继承](#Flask-Bootstrap 的作用:把bootstrp包装成jinja2可用的模板,从而实现模板继承)
- [bootstrap = Bootstrap(app) 是Flask-Bootstrap的1种初始化方式。app是flask应用的实例](#bootstrap = Bootstrap(app) 是Flask-Bootstrap的1种初始化方式。app是flask应用的实例)
- 3.3自定义错误界面
-
- [@app.errorhandler(错误码) 就是注册一个"遇到这个错误就执行的函数"](#@app.errorhandler(错误码) 就是注册一个“遇到这个错误就执行的函数”)
-
- [@app.errorhandler(404) 页面不存在](#@app.errorhandler(404) 页面不存在)
- [@app.errorhandler(500) 服务器出错](#@app.errorhandler(500) 服务器出错)
- 3.4 链接
-
- [视图函数名和端点名不一致时,只能使用端点名。Flask 只认端点名 来生成 URL](#视图函数名和端点名不一致时,只能使用端点名。Flask 只认端点名 来生成 URL)
- [为什么不能直接写 URL?](#为什么不能直接写 URL?)
- [url_for() 用 端点名 生成 URL](#url_for() 用 端点名 生成 URL)
-
- [为什么 浏览器内导航 → 只需要相对 URL 就够了?相对url指不带域名和端口](#为什么 浏览器内导航 → 只需要相对 URL 就够了?相对url指不带域名和端口)
- [动态路由和 url_for()](#动态路由和 url_for())
- 添加查询参数
- [3.5 静态文件](#3.5 静态文件)
-
- 什么叫「静态文件」?
- [Flask 默认有一个 /static/<filename> 路由](#Flask 默认有一个 /static/<filename> 路由)
- 默认设置下,Flask在应用目录中名为static的子目录中寻找静态文件。应用目录是哪个?创建flask对象的那个python文件所在的目录
- [为什么要用 url_for('static', ...)?](#为什么要用 url_for('static', ...)?)
- [url_for('static', ...) 是什么意思?static:static路由端点名filename:static 文件夹里的路径](#url_for('static', ...) 是什么意思?static:static路由端点名filename:static 文件夹里的路径)
- [link icon指定浏览器标签页左上角的小图标](#link icon指定浏览器标签页左上角的小图标)
-
- [`<link> `永远写在 `<head>` 里,使用xx类型的外部资源,它的位置在xx](#
<link>永远写在<head>里,使用xx类型的外部资源,它的位置在xx) -
- [href = hyper reference(超链接引用),告诉浏览器:那个资源"在哪里"](#href = hyper reference(超链接引用),告诉浏览器:那个资源“在哪里”)
-
- [icon 就是我们说的 网站图标](#icon 就是我们说的 网站图标)
- [rel="stylesheet" 页面的样式](#rel="stylesheet" 页面的样式)
- rel="preload"提前加载一个资源
- [为什么不是 src?src:把资源"塞进"页面,href:建立引用关系](#为什么不是 src?src:把资源“塞进”页面,href:建立引用关系)
- [rel 决定"是什么关系"](#rel 决定“是什么关系”)
- 为什么不是页面里的某个图标?
- [`<link> `永远写在 `<head>` 里,使用xx类型的外部资源,它的位置在xx](#
- 使用Flask-Moment本地化日期和时间
-
- [数据库存 UTC。服务器用 UTC。浏览器负责显示本地时间](#数据库存 UTC。服务器用 UTC。浏览器负责显示本地时间)
- [初始化Flask-Moment。创建实例并绑定 Flask 应用](#初始化Flask-Moment。创建实例并绑定 Flask 应用)
- [Flask-Moment(flask扩展,在模板中处理和显示时间) 和依赖](#Flask-Moment(flask扩展,在模板中处理和显示时间) 和依赖)
-
- [moment.include_moment() 在 HTML 里插入加载 Moment.js 的 <script> 标签](#moment.include_moment() 在 HTML 里插入加载 Moment.js 的 <script> 标签)
- [Flask-Moment (生成模板代码的flask扩展)和 Moment.js 的关系](#Flask-Moment (生成模板代码的flask扩展)和 Moment.js 的关系)
- [为什么还要放在 scripts 块?](#为什么还要放在 scripts 块?)
-
- [HTML 的 <script> 就是浏览器里的"程序"](#HTML 的 <script> 就是浏览器里的“程序”)
- 例子
-
- [moment() Flask-Moment 提供的模板辅助函数。把 Python 的 datetime 变成 HTML + JavaScript 代码。在浏览器中自动本地化时间](#moment() Flask-Moment 提供的模板辅助函数。把 Python 的 datetime 变成 HTML + JavaScript 代码。在浏览器中自动本地化时间)
- [format('LLL')。'LLL' 是 Moment.js 里的格式选项](#format('LLL')。'LLL' 是 Moment.js 里的格式选项)
- [moment(xx).fromNow() 计算 xx 相对于"现在" 是多久。显示相对时间](#moment(xx).fromNow() 计算 xx 相对于“现在” 是多久。显示相对时间)
-
- [refresh=True 每隔一段时间自动刷新](#refresh=True 每隔一段时间自动刷新)
- [Flask-Moment 假定服务器端应用处理的时间戳是"纯正的"datetime对象,且使用 UTC 表示。](#Flask-Moment 假定服务器端应用处理的时间戳是“纯正的”datetime对象,且使用 UTC 表示。)
- 怎么让时间用不同语言显示。moment.locale
Flask Web开发:基于Python的Web应用开发实战.第2版.pdf
摘要,视图函数只负责请求 → 响应,业务逻辑(数据处理)和表现逻辑(HTML 页面生成)要分开,模板(Jinja2) 用来渲染页面 → 表现逻辑移到模板中


什么是业务逻辑 vs 表现逻辑

为什么要用模板【带占位符的文件】(Template)?


渲染(Rendering)是什么?把模板里的占位符替换成真实值

3.1 Jinja2模板引擎
Jinja2模板就是一个包含响应文本的文件
渲染模板
默认情况下,Flask在应用目录中的templates子目录里寻找模板。应用目录是哪个?创建 Flask 对象的那个 Python 文件所在目录




render_template() 把模板和数据结合,并渲染成最终的html,返给浏览器


3.1.2 变量
访问字典中的值
A value from a dictionary: {{ mydict['key'] }}.

访问列表中的值
A value from a list: {{ mylist[3] }}.

使用变量作为索引
A value from a list, with a variable index: {{ mylist[myintvar], mydict[mykey] }}.

调用对象方法
A value from an object's method: {{ myobj.somemethod() }}.

可以在模板里几乎和 Python 一样操作数据,

过滤器 把左边的值传给右边的过滤器

safe:渲染时不转义 HTML

capitalize:首字母大写,其他小写

lower:全部小写

upper:全部大写

title:每个单词首字母大写

trim:去掉首尾空格

striptags:去掉 HTML 标签

链式调用:组合多个过滤器


3.1.3 控制结构
Jinja2 提供了多种控制结构,可用来改变模板的渲染流程
条件判断(if/else)

循环(for)

宏(macro) --- 模板里的"函数"



宏的导入(import)

Jinja2 宏导入从 Flask 的模板根目录 (templates) 开始找,相对路径写文件名或子目录路径即可。


include --- 引入模板片段。直接把另一个模板内容原封不动插入。

从 Flask 的模板根目录开始找(默认模板根目录)


include ------ 引入模板片段, import ------ 引入宏(宏是函数)



不能include宏,import模板

模板继承(extends / block / super)









Jinja2 的重复使用代码片段方法总结,宏,include,模板继承

3.2 使用Flask-Bootstrap集成Bootstrap
Bootstrap 是什么?网页美化工具包




Flask-Bootstrap 的作用:把bootstrp包装成jinja2可用的模板,从而实现模板继承

bootstrap = Bootstrap(app) 是Flask-Bootstrap的1种初始化方式。app是flask应用的实例
初始化 Flask-Bootstrap 之后,就可以在应用中使用一个包含所有 Bootstrap 文件和一般结构的基模板。
怎么用 Flask-Bootstrap 给的基模板?
利用 Jinja2 的模板继承机制来扩展这个基模板




| 区块名 | 说明 | 位置 / 用法 | 举例 |
|---|---|---|---|
| doc | 整个 HTML 文档 | 最外层 <html>...</html> |
{% block doc %}{% endblock %} 可以覆盖整张网页 |
| html_attribs | <html> 标签的属性 |
比如 lang="en" 或 class="no-js" |
{% block html_attribs %}lang="en"{% endblock %} |
| html | <html> 标签中的内容 |
<head> 和 <body> 的全部 |
基模板内部用,不常直接改 |
| head | <head> 标签里的内容 |
放 CSS 链接、meta 标签等 | {% block head %}<link rel="stylesheet"...>{% endblock %} |
| title | <title> 标签里的内容 |
浏览器标签页标题 | {% block title %}Flasky{% endblock %} |
| metas | <meta> 标签集合 |
页面编码、视口、SEO 等 | {% block metas %}<meta charset="utf-8">{% endblock %} |
| styles | CSS 样式声明 | 自定义样式 | {% block styles %}body {background: #f0f0f0;}{% endblock %} |
| body_attribs | <body> 标签的属性 |
比如 class="home-page" |
{% block body_attribs %}class="home"{% endblock %} |
| body | <body> 标签中的内容 |
主要内容容器 | 内部包含 navbar 和 content,你一般不直接改 |
| navbar | 用户自定义导航栏 | 页面顶部菜单 | {% block navbar %}...导航栏HTML...{% endblock %} |
| content | 用户自定义页面内容 | 页面主体 | {% block content %}<h1>Hello!</h1>{% endblock %} |
| scripts | 文档底部的 JavaScript | 放 JS 文件或脚本 | {% block scripts %}<script src="..."></script>{% endblock %} |

3.3自定义错误界面
@app.errorhandler(错误码) 就是注册一个"遇到这个错误就执行的函数"



@app.errorhandler(404) 页面不存在
Flask 找不到路由 → 自动生成 404 错误
如果不返回 404 状态码,浏览器会默认返回 200 OK,不符合标准

@app.errorhandler(500) 服务器出错


3.4 链接
url_for() 函数最简单的用法是以视图函数名(或者app.add_url_route()定义路由时使用的端点名)作为参数,返回对应的URL。
Flask 只认端点名 来生成 URL
视图函数名和端点名不一致时,只能使用端点名。Flask 只认端点名 来生成 URL

为什么不能直接写 URL?

url_for() 用 端点名 生成 URL


为什么 浏览器内导航 → 只需要相对 URL 就够了?相对url指不带域名和端口



动态路由和 url_for()

添加查询参数

3.5 静态文件
什么叫「静态文件」?


Flask 默认有一个 /static/ 路由

默认设置下,Flask在应用目录中名为static的子目录中寻找静态文件。应用目录是哪个?创建flask对象的那个python文件所在的目录



为什么要用 url_for('static', ...)?

url_for('static', ...) 是什么意思?static:static路由端点名filename:static 文件夹里的路径

link icon指定浏览器标签页左上角的小图标
html
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
兼容性写法:
shortcut icon:老浏览器 / IE
icon:现代浏览器、
<link rel="icon">(以及旧的 shortcut icon)在 HTML 标准里的含义就是页面的图标(page icon / favicon)

<link> 永远写在 <head> 里,使用xx类型的外部资源,它的位置在xx


href = hyper reference(超链接引用),告诉浏览器:那个资源"在哪里"



icon 就是我们说的 网站图标

rel="stylesheet" 页面的样式

rel="preload"提前加载一个资源

为什么不是 src?src:把资源"塞进"页面,href:建立引用关系

rel 决定"是什么关系"

为什么不是页面里的某个图标?

使用Flask-Moment本地化日期和时间
数据库存 UTC。服务器用 UTC。浏览器负责显示本地时间


初始化Flask-Moment。创建实例并绑定 Flask 应用

Flask-Moment(flask扩展,在模板中处理和显示时间) 和依赖
Flask-Moment是一个Flask扩展,能简化把Moment.js集成到Jinja2模板中
的过程。

moment.include_moment() 在 HTML 里插入加载 Moment.js 的


从\site-packages\flask_bootstrap\templates\bootstrap\base.html可以看到基模板有scripts块。【点击bootstrap = Bootstrap(app)初始化的 Bootstrap类,可以看到上述位置】


Flask-Moment (生成模板代码的flask扩展)和 Moment.js 的关系
Flask-Moment(Python 扩展)只是 生成模板代码,
服务器端 Flask-Moment 只是生成 HTML/JS
Flask-Moment 不处理时间,只帮你生成浏览器需要的 HTML 和 JS,让 Moment.js 在客户端执行真正的时间处理






为什么还要放在 scripts 块?

HTML 的

例子
moment() Flask-Moment 提供的模板辅助函数。把 Python 的 datetime 变成 HTML + JavaScript 代码。在浏览器中自动本地化时间

format('LLL')。'LLL' 是 Moment.js 里的格式选项


moment(xx).fromNow() 计算 xx 相对于"现在" 是多久。显示相对时间


refresh=True 每隔一段时间自动刷新

Flask-Moment 假定服务器端应用处理的时间戳是"纯正的"datetime对象,且使用 UTC 表示。
纯正的时间戳,英文为naive time,指不包含时区的时间戳;
细致的时间戳,英文为aware time,指 包含时区的时间戳。
怎么让时间用不同语言显示。moment.locale








