Flask Web开发 3.0 模板
想要开发出易于维护的程序,关键在于编写形式简洁且结构良好的代码。到目前为止我们接触到的示例都太简单,无法说明这一点,但Flask视图函数的两个完全独立的作用却被融合在了一起,这就会产生一个问题。
视图函数的作用很简单,即生成请求的响应。 对于简单的请求来说,这就足够了,但是一般而言,请求会改变程序的状态,而这种变化也会在视图函数中产生。
例如,用户在网站注册了一个新账户。用户在表单中输入电子邮件地址和密码,然后点击提交按钮。服务器接收到包含用户输入数据的请求,然后Flask把请求分发到处理注册请求的视图函数。这个视图函数需要访问数据库,添加新用户,然后生成响应回送浏览器。这两个过程分别称为业务逻辑和表现逻辑。
把业务逻辑和表现逻辑混在一起会导致代码难以理解和维护。假设要为一个大型表格构建一个HTML代码,表格中的数据由数据库中读取的数据以及必要的HTML字符串连接在一起。把表现逻辑移到模板中能够提升程序的可维护性。
模板是一个包含响应文本的文件,其中包含用占位变量表示的动态部分,其具体值只在请求的上下文中才能知道。使用真实值替换变量,再返回最终得到的响应字符串,这一过程称为渲染。为了渲染模板,Flask使用了一个名为Jinja2的强大模板引擎。
3.1 Jinja2模板引擎
形式最简单的Jinja2模板就是一个包含响应文本的文件。下面的例子是一个Jinja2模板,它和第二章helloworld示例中的index()视图函数的响应一样。Jinja2模板要放在整个Flask Web 工程的templates文件夹里。
<h1>Hello world!</h1>
如果视图函数返回的响应中包含一个使用变量表示的动态部分,利用Jinja2也可以实现。
<h1>Hello,{{ name }}!</h1>
3.1.1 渲染模板
默认情况下,Flask在程序文件夹的templates文件夹中寻找模板。在示例程序的下一个版本中,要把前面定义的两个模板放在templates文件夹下,分别命名为index.html和user.html。然后,我们需要改一下程序中的视图函数,以便渲染这些模板。
from flask import render_template
@app.route('/')
def index():return render_template('index.html')@app.route('/user/<name>')
def user(name):return render_template('user.html',name = name)if __name__ == '__main__':app.run(debug=True)
Flask提供的render_template函数把Jinja2模板引擎集成到了程序中,render_template函数的第一个参数是模板的文件名,随后的参数都是键值对,表示模板中的变量对应的真实值。在这段代码中第二个模板收到名为name的变量。其中左边的name表示参数名,就是模板中使用的占位符;右边是当前作用域中的变量,表示同名参数的值。
3.1.2 变量
上面的代码在模板中使用的{{ name }}结构表示一个变量,它是一种特殊的占位符,告诉模板引擎这个位置的值从渲染模板时使用的数据中获取。
Jinja2能识别所有类型的变量,甚至是一些复杂的类型,例如列表、字典和对象。在模板中使用变量的一些示例如下:
<p>A value from a dictionary:{{ mydict['key'] }}.</p>
<p>A value from a list:{{ mylist[3] }}.</p>
<p>A value from a list,with a variable index:{{ mylist[myintvar] }}.</p>
<p>A value from an object's method:{{ myobj.somemethod }}.</p>
可以使用过滤器修改变量,过滤器名添加在变量名之后,中间使用竖线分割。例如,下面模板使用首字母大写形式显示变量name的值
<h1>Hello,{{ name|capitalize }}!</h1>
Jinja2部分常用的过滤器:
- safe:渲染值时不进行转义
- capitalize:把值的首字母转换成大写,其他字母转换成小写
- lower:把值转换成小写形式
- upper:把值转换成大写形式
- title:把值中的每个单词的首字母都转换成大写
- trim:把值的首尾空格去掉
- striptags:渲染之前把值中所有的HTML标签都删掉
3.1.3 控制结构
{% if user %}Hello ,{{ user }}!
{% else %}Hello,Stranger!
{% endif %}
另一种常见需求是再模板中渲染一组元素。可以用for 循环实现这一需求:
<ul>{% for comment in comments %}<li>{{ comment }}</li>{% endfor %}
</ul>
Jinja2还支持宏。宏类似于Python代码中的函数,例如
<ul>{% for comment in comments %}{{ render_comment(comment)}}{% endfor %}
</ul>
为了重复使用宏,我们可以将它保存在单独的文件夹中,然后在需要使用的模板中导入:
{% import 'macros.html' as macros %}
<ul>{% for comment in comments %}{{ macros.render_comment(comment) }}
</ul>
需要在多处重复使用的模板代码片段中写入单独的文件,再包含再所有模板中,以避免重复
{% include 'comment.html' %}
另一种重复使用代码的强大方式是模板继承,它类似于Python代码中的类继承。首先创建一个名为base.html的基模板:
<html>
<head>{% block head %}<title>{% block title %}{% endblock %} - My Application </title>{% endblock %}
</head>
<body>{% block body %}{% endblock %}
</body>
</html>
block标签定义的元素可以在衍生模板中进行修改。在本例中我们定义了一个名为head、title和body的块。注意,title包含在head中。我们可以使用基模板衍生一个模板:
{% extends 'base.html' %}
{% block title %}Index{% endblock %}
{% block head %}{{ super() }}<style></style>
{% endblock %}
{% block body %}
<h1>Hello,World!</h1>
{% endblock %}
extends指令声明这个模板衍生自base.html。在该指令之后,基模板中的三个块被重新定义,模板引擎会将其插入适当的位置。注意新定义的head块,在基模板中其内容不是空的,所以使用super()来获取原来的内容。
3.2 使用Flask-Bootstrap集成Twitter Bootstrap
from flask import Flask
from flask_bootstrap import Bootstrap
app = Flask(__name__)
bootstrap = Bootstrap(app)
{% extends "bootstrap/base.html" %}
{% block title %}Flasky{% endblock %}
{% block navbar %}
<div class="navbar navbar-inverse" role="navigation"><div class="container"><div class="navbar-header"><button type = "button" class="navbar-toggle"data-toggle="collapse" data-target=".navbar-collapse"><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="/">Flasky</a></div><div class="navbar-collapse collapse"><ul class="nav navbar-nav"><li><a href="/">Home</a> </li></ul></div></div>
</div>
{% endblock %}{% block content %}
<div class="container"><div class="page-header"><h1>hello ,{{ name }}!</h1></div>
</div>
{% endblock %}
Jinja2中的extends指令从Flask-Bootstrap中导入bootstrap/base.html,从而实现模板继承。Flask-Bootstrap中的基模板提供了一个网页框架,引入了Bootstrap中的所有CSS和JavaScript 文件。基模板中定义了可在衍生模板中进行重定义的块。block和endblock指令定义的块中的内容可添加到基模板中。
![](/assets/blank.gif)
块名 | 说明 |
doc | 整个HTML文档 |
html.attribs | <html>标签的属性 |
html | <html>标签中的内容 |
head | <head>标签中的内容 |
title | <title>标签中的内容 |
metas | 一组<meta>标签 |
styles | 层叠样式表定义 |
body_aattribs | <body>标签的属性 |
body | <body>标签中的内容 |
navbar | 用户定义的导航条 |
content | 用户定义的页面内容 |
scripts | 文档底部的JavaScript声明 |
该表中的很多块都是Flask-Bootstrap自用的,如果直接进行重定义可能会出现一些问题。例如,Bootstrap所需的文件在styles和scripts块中声明。如果程序需要向已经有内容的块中添加新内容,必须使用Jinja2提供的Super()函数。例如,如果要在衍生模板中添加新的JavaScript文件,需要这么定义scripts块。
{% block scripts %}
{{ super() }}
<script type="text/javascript" src="my-script.js"></script>
{% endblock %}
3.3 自定义错误页面
@app.errorhandler(404)
def page_not_found(e):return render_template('404.html'),404@app.errorhandler(500)
def internal_server_error(e):return render_template('500.html'),500
和视图函数一样,错误处理程序也会返回响应。它们还返回与该错误对应的数字状态码。
{% extends "bootstrap/base.html" %}
{% block title %}Flasky{% endblock %}
{% block navbar %}
<div class="navbar navbar-inverse" role="navigation"><div class="container"><div class="navbar-header"><button type = "button" class="navbar-toggle"data-toggle="collapse" data-target=".navbar-collapse"><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="/">Flasky</a></div><div class="navbar-collapse collapse"><ul class="nav navbar-nav"><li><a href="/">Home</a> </li></ul></div></div>
</div>
{% endblock %}{% block content %}
<div class="container">{% block page_content %}{% endblock %}
</div>
{% endblock %}
这个模板的整个content块中只有一个<div>容器,其中包含了一个名为page_content的新的空块,块中的内容由衍生模板定义。
{% extends 'base.html' %}
{% block title %}Flasky - Page Not Found{% endblock %}
{% block page_content %}
<div class = 'page-header'><h1> Not Found .</h1>
</div>
{% endblock %}
同样的,现在我们的user.html也可以通过继承新的base.html来简化:
{% extends 'base.html' %}
{% block title %}Flasky{% endblock %}
{% block page_content %}
<div class = 'page-header'><h1>Hello,{{ name }}!</h1>
</div>
{% endblock %}
3.4 链接
3.5 静态文件
{% block head %}{{ super() }}<link rel="short icon" href="{{ url_for('static',filename ='favicon.icon') }}" type="image/x-icon"/><link rel="icon" href="{{ url_for('static',filename ='favicon.icon') }}" type="image/x-icon"/>
{% endblock %}
图标的声明会插入head块的末尾。注意如何使用super()保留基模板中定义的块的原始内容。
3.6 使用Flask-Moment本地化日期和时间
from flask_moment import Moment
app = Flask(__name__)
moment = Moment(app)
除了moment.js,Flask-Moment还依赖jquery.js。要在HTML文档的某个地方引入这两个库,可以直接引入,这样可以选择使用哪个版本,也可以使用扩展提供的辅助函数,从内容分发网络(CDN)中引入通过测试的版本。Bootstrap已经引入了jquery.js,因此只需引入moment.js即可。下面展示了如何在基模板的scripts块中引入这个库。
{% block scripts %}
{{ super() }}
{{ moment.include_moment() }}
{% endblock %}
为了处理时间戳,Flask-Moment向模板开放了moment类。下面的代码把变量current_time传入模板进行渲染
from datetime import datetime
@app.route('/')
def index():return render_template('index.html',curren_time = datetime.utcnow())
示例 templates/index.html:使用Flask-Moment渲染时间戳 (代码运行没有效果,暂不清楚原因)
<p>The local date and time is {{ moment(curren_time).format('LLL') }}.</p>
<p>That was {{ moment(curren_time).fromNow(refresh=True) }}</p>
format('LLL')根据客户端电脑中的时区和区域设置渲染日期和时间。参数决定了渲染的方式,‘L’到‘LLLL’分别对应不同的复杂度。format()函数还可接受自定义的格式说明符。
![](/assets/blank.gif)
Flask Web开发 3.0 模板相关推荐
- Flask Web开发-1.2模板及网页设计基础
目录: 前言: 一,Jinja2模板引擎 1.渲染模板 2.变量 3.控制结构 二,使用Flask-Bootstrap集成Twitter Bootstrap 三,自定义错误页面 四,链接 五,静态文件 ...
- python flask html模板,python flask web开发实战 Jinja2模板
templates/index.html Hello World! templates/user.html Hello, {{ name }}! 渲染模板: from flask import Fla ...
- Flask Web开发基础实战-1.0用户认证与注册模块
目录: 前言: 一,账户密码安全性 使用Werkzeug实现密码散列 二,创建登录的认证蓝本 三,Flask-Login认证用户 1.用于登录的用户数据库模型 2.保护路由 3.添加登录表单 4.登入 ...
- flask web开发是前端还是后端_Flask Web开发实战:入门、进阶与原理解析 PDF 全格式版...
给大家带来的一篇关于Flask相关的电子书资源,介绍了关于Flask.Web.开发实战方面的内容,本书是由机械工业出版社出版,格式为PDF,资源大小12.2M,李辉编写,目前豆瓣.亚马逊.当当.京东等 ...
- 《Flask Web开发:基于Python的Web应用开发实战》笔记(原创)
内容提要 在学习"狗书"<Flask Web开发:基于Python的Web应用开发实战>的过程中,一直遇到各种各样的坑.该书的第一部分是"Flask简介&qu ...
- Flask Web开发:基于Python的Web应用开发实战
<Flask Web开发:基于Python的Web应用开发实战> 虽然简单的网站(Flask+Python+SAE)已经上线,但只是入门.开发大型网站,系统地学习一遍还是有必要的. 201 ...
- 《Flask Web开发实战:入门、进阶与原理解析》读书笔记
写在前面 学docker编排,有一个用Flask框架的Demo,感觉挺方便,所以学习下 基于<Flask Web开发实战:入门.进阶与原理解析>做的读书笔记 个人还是比较喜欢看书,看书的话 ...
- Flask Web开发入门
Flask Web开发入门(八)之文件上传 https://blog.csdn.net/kangkanglou/article/details/79027425 前端:详情见上面的链接/也可以直接用f ...
- 《Flask Web开发——基于Python的Web应用开发实践》一字一句上机实践(上)
目录 前言 第1章 安装 第2章 程序的基本结构 第3章 模板 第4章 Web表单 第5章 数据库 第6章 电子邮件 第7章 大型程序的结构 前言 学习Python也有一个半月时间了,学到现在感觉还是 ...
最新文章
- NFV — 系统架构
- accp8.0转换教材第11章Ajax交互扩展理解与练习
- 一个简单的插件框架示例
- 计算机网络基础学测,《计算机网络技术基础》第二1章单元学习测习题-20210622072616.docx-原创力文档...
- File stdin , line 1
- 分布式搜索elasticsearch集群监控工具bigdesk
- 二十八种未授权访问漏洞合集(暂时最全)
- MogDB大对象LargeObject存取测试
- 红橙Darren视频笔记 旋转加载界面
- FeatureLayer.FeatureClass.Feature --以及图层最容易理解的讲解;如有巧合,一定是别人抄袭(Arcgis辅助理解)
- 牛市买基金好还是股票好?买基金会翻倍吗?
- c51单片机小车代码解释
- VSCode 中怎样快速切换多个项目
- 人力资源管理-输入、输出、工具和技术
- CDH5: 使用parcels配置lzo
- 和互联网公司服务器有关的一些情况
- 主流的第三方直播SDK对比(腾讯云、即构、阿里云、声网、网易云信、网宿)
- Linux下socket编程:TCP连接
- Java中hasNext()的作用
- 关于Context的理解(转)
热门文章
- 趣味编程故事|java进程占用cpu过高怎么办,别急我来帮你
- MMRotate 全面升级,新增 BoxType 设计
- 【正点原子sys、delay、usart文件夹介绍】
- python 股票指标库talib_talib金融库怎么用?
- win10设置网络打印机
- 手电筒安卓_安卓实用小工具!智能工具箱特别版本安卓软件
- 集合去重,取交集并集差值
- 台式机下成功在windows10的基础上安装Ubuntu 18.04 LTS 系统(详细教程)
- 没学历的IT人生没那么悲催,献给程序员们
- android 4.4 源码编译,Android 4.4源码编译过程