目录
1.Flask
Flask提供了一组工具和库,帮助开发者快速构建Web应用程序。它使用Python的装饰器语法来定义路由和视图函数,使用简洁的方式处理HTTP请求和响应。
•Flask不强制使用特定的数据库或模板引擎,而是允许开发者根据需求选择适合的工具。
•Flask自带开发服务器,无须安装比如Tomcat、JBoss、Apache等网络服务器。
•基于Flask开发的程序可开启调试状态(app.debug = True),出现异常时,Flask程序会同时向启动Python程序的控制台和HTTP客户端发送错误信息
•Flask完全基于Unicode编码格式,对制作非纯ASCII字符集的网站而言非常方便。HTTP协议要求每次传输时需要在请求头显式指定编码格式,Flask程序默认会为请求头指定UTF-8编码,使开发者无须担心编码问题。
注:Flask只保留Web开发的核心功能,不包括用户认证、表单验证、邮件发送等功能,但可在Fask官网找到相应的扩展包对网站进行个性化定制。
Flask默认依赖两个外部库:Werkzeug WSGI工具包和Jinja2模板引擎
WSGI:
WSGI(Web服务器网关接口)是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口,它制定了一套通信标准,保证Web服务器可以跟Web应用程序之间相互通信。Flask程序完全兼容WSGI,它能够运行到任何Web服务器。
Werkzeug WSGI:
Werkzeug是一个WSGI工具包,他可以作为一个Web框架的底层库。 werkzeug 不是一个web服务器,也不是一个web框架,而是一个工具包,它封装好了很多 Web 框架的东西,例如 Request,Response 等等。
Jinja2:
Jinja2模板,模板简单来说就是一个其中包含 占位变量 表示 动态 部分的文件,模板文件在经过动态赋值后,返回给用户。
- JinJa2模板引擎将HTML页面和应用程序联系起来。
- JinJa2模板引擎由Django模板引擎发展而来,但比Django模板引擎更高效。
- Jinja2模板引擎使用配制的语义系统,它不仅提供了灵活的模板继承技术,还可以自动防止(XSS)跨站攻击。
2.安装Flask
pip install flask
安装Flask会对应6个依赖包
依赖包 | 说明 |
Jinja2 | 模板渲染引擎 |
MarkupSafe | HTML字符转义工具 |
Werkzeug | WSGI工具集,它封装了Web框架中的很多内容,包含请求、响应、WSGI开发服务器、调试器和重载器 |
click | 命令行工具 |
colorama | 命令行彩色显示工具 |
itsdangerous | 提供各种加密签名功能 |
requirements.txt
不同的Flask项目可能会依赖不同的虚拟环境,若要在新计算机中运行项目,就需要重复为该项目配置一套相同的虚拟环境,为了区分和记录每个项目的依赖包及其版本,以便在新计算机中复现项目的虚拟环境,我们可以通过一个requirements.txt文件记录项目的所有依赖包及其版本号,以便在新计算机中实现一键安装的效果。
需要说明的是,requirements.txt文件的名称是开发者之间约定俗成的,也可以进行重新命名。
通过pip命名将环境依赖的扩展包及其版本号记录到requirements.txt文件中
pip freeze > requirements.txt
在另一台计算机中通过运行以下pip命令将记录的依赖包及其版本号安装相应版本的依赖包
pip install -r requirements.txt
3.Flask程序
(1)Flask程序的运行
# 新建一个名称为app.py的文件
from flask import Flask #导入Flask类
app = Flask(__name__) # 实例化Flask类
@app.route("/") # 定义视图函数,并为该函数注册路由
def hello_flask():
return '<p>Hello, Flask!</p>'
if __name__ == '__main__':
app.run() # 启动开发服务器
注:这里可以直接运行程序代码,也可以在命令行窗口执行flask run命令启动程序(Ctrl + C可以退出)
(2)FLASK_APP和FLASK_DEBUG
FLASK_APP
执行flask run命令时,Flask会使用内置的开发服务器运行程序。默认会假设程序存储在名为app.py或者wsgi.py的文件中。如果使用其他名称,则要设置系统环境变量FLASK_APP,告诉Flask要启动的对应程序。
- Linux系统:export FLASK_APP=hello.py
- Windows CMD:set FLASK_APP=hello.py
- Windows PowerShell: $env:FLASK_APP ="hello.py"
FLASK_DEBUG
FLASK_DEBUG用于开启调试模式(debug mode)。调试模式开启后,当程序出错,浏览器页面上会显示错误信息;代码出现变动后,程序会自动重载。
> set FLASK_DEBUG=1
> flask run
或者
>flask run --debug
(3)程序的基本结构
Hello Flask程序包含3个比较重要的部分,分别是Flask类、开发服务器、路由与视图。
Flask类
Flask类是flask包中的核心类,该类中封装了很多与Flask程序相关的方法,通过这些方法可以轻松地对Flask程序进行相应的操作。所有的Flask程序中必须要创建一个Flask类的对象。
app=Flask(__name__)
必须参数__name__是Flask中一个特殊的变量,用于保存程序主模块或者包的名称。可选参数有以下:
•static_folder:用于指定存放静态文件的文件夹名称,默认值为static。
•static_url_path:用于指定前端访问静态文件的路径,默认值为static_folder的名称。
•template_folder:用于指定存放模板文件的文件夹名称,默认为应用程序根路径下的templates文件夹。
开发服务器
Flask的依赖包Werkzeug提供了一个简易的开发服务器
使用开发服务器有两种方式,一种为命令行启动,另一种是通过代码方式,即调用Flask类的对象的run()方法
app.run()
•host:运行当前程序的主机名称,默认值为'127.0.0.1'或'localhost'。
•port:运行当前程序的主机对应的端口号,默认值为5000。
•debug:是否启用调试模式,默认值为False。
路由与视图
- 路由是一种目前主流的Web框架中应用的技术,用于帮助用户直接根据URL访问某个页面,而无须再从主页导航到这个页面。当初始化Flask类对象时,会注册程序中所有的URL规则,一旦用户在浏览器发送访问某个页面的URL请求后,服务器便会将该URL请求交给Flask程序,这时Flask程序会根据URL规则找到与之关联的视图。
- 在Flask中,视图是Python函数或Python类,用于对浏览器发送的请求进行处理,并返回响应内容给Web服务器。视图返回的响应内容既可以是一个包含HTML代码的字符串,也可以表单等。
在Hello Flask程序中,定义视图函数及URL规则代码如下:
@app.route("/")
def hello_flask():
return '<p>Hello, Flask!</p>'
4.路由
(1)注册路由
在Flask程序中,浏览器通过URL发送HTTP请求给Web服务器,Web服务器再将HTTP请求转发给Flask程序。Flask程序接收到HTTP请求后,需要知道Flask程序中哪部分代码对这个请求进行处理。为此,Flask程序保存了一个URL与视图函数或类的映射关系,建立映射关系的过程称为注册路由。
在Flask中,注册路由一般分为两种方式,一种方式是通过route()方法进行注册,另一种方式是通过add_url_rule()方法进行注册。
route()
route()是Flask类提供的方法,该方法用于将视图函数与特定的URL建立关联,当通过浏览器访问URL时程序内部自动调用与之关联的视图函数。
route(rule, methods, **options)
•rule:必选参数,表示URL规则字符串,该字符串必须以“/”开始。
•methods:可选参数,表示HTTP请求方法。
•**options:可选参数,表示传递给底层werkzeug.routing.Rule对象的额外选项。
#route()方法需要以装饰器的形式写在视图函数的上方。
from flask import Flask
app = Flask(__name__)
@app.route('/index') # 通过route()方法注册路由,URL规则为/index
def index():
return f'<h1>这是首页!</h1>'
if __name__ == '__main__':
app.run()
注:若URL规则字符串以“/”结尾,但用户访问URL时并没有在URL末尾附加“/”,则会自动重定向到附加了“/”的页面;若URL规则字符串的末尾没有附加“/”,但用户通过URL访问页面时在URL末尾附加了“/”,则会出现404页面。
结果:
add_url_rule()
add_url_rule()也是Flask类提供的方法,一般需要传递URL和URL关联的函数名。
add_url_rule(rule, endpoint=None, view_func=None,provide_automatic_options=None, **options)
•rule:必选参数,表示URL规则字符串,必须以’/’开始。
•endpoint:可选参数,表示端点名称。
•view_func:可选参数,表示与端点关联的视图函数名,只写函数名,不需要加括号。
•methods:可选参数,表示定义的HTTP请求方法。
•**options:可选参数,表示传递给底层werkzeug.routing.Rule对象的额外选项。
#add_url_rule()方法注册路由,使视图函数与URL建立关联
from flask import Flask
app = Flask(__name__)
def index_new():
return f'<h1>这是首页1!</h1>'
# 通过add_url_rule()方法注册路由
app.add_url_rule(rule='/index1', view_func=index_new)
if __name__ == '__main__':
app.run()
结果:
注:route()方法内部其实调用了add_url_rule()方法,route()方法的用法更简洁,无需传入与URL规则关联的视图函数名。
在Flask程序中,一个视图函数也可以绑定多个URL,当浏览器访问这些URL时会触发Flask程序中的同一个视图函数,也就是说在浏览器中展示的效果相同。
@app.route('/homepage')
@app.route('/index')
def index():
return f'<h1>这是首页!</h1>
(2)URL传递参数
变量传递
当调用route()或add_url_rule()方法注册路由时,可以在URL规则字符串中加入尖括号包裹的变量,用于标记URL中动态变化部分的内容,之后将该变量作为参数传递给视图函数。
from flask import Flask
app = Flask(__name__)
@app.route('/<page>') # URL规则字符串中加入尖括号变量page
def page_num(page): # 将page参数传递给视图函数
return f'当前为第{page}页'
if __name__ == '__main__':
app.run()
结果:
converter
当URL向视图函数传递参数时,如果需要限定参数的类型,那么可以通过转换器指定参数的类型。
<converter:variable_name>
converter表示转换器,它支持两种类型的转换器,分别是内置转换器和自定义转换器。
•内置转换器
如果为参数明确指定了转换器,那么URL中传递的参数必须符合转换器要求的数据类型。
转换器 | 说明 |
string | 默认值,匹配非空字符串,但不包含“/” |
any | 匹配给定的一系列值中的某一个元素 |
int | 匹配整型 |
float | 匹配浮点型 |
path | 与string类似,匹配非空字符串,但允许字符串中包含“/” |
uuid | 匹配UUID字符串 |
from flask import Flask
app = Flask(__name__)
@app.route('/<int:page>') # page显式指定为int
def page_num(page): # 将page参数传递给视图函数
return f'当前为第{page}页'
if __name__ == '__main__':
app.run()
page参数一定要为ing,如果不是,就会出现“Not Found”参数
•自定义转换器
来看一个例子,to_python() 方法将从 URL 中获取的字符串类型的值转换为整型,并加上100。
from flask import Flask, url_for
from werkzeug.routing import BaseConverter
# 定义自定义转换器类
class MyIntConverter(BaseConverter):
def to_python(self, value):
try:
return int(value) + 100
except ValueError:
pass
# 创建Flask应用程序
app = Flask(__name__)
# 注册自定义转换器
app.url_map.converters['myint'] = MyIntConverter
# 定义路由和视图函数
@app.route('/page/<myint:page>')
def show_page(page):
return f'当前为第{page}页'
if __name__ == '__main__':
app.run()
结果:
5.请求处理
Flask程序可以在使用装饰器route()或add_url_rule()方法注册路由时传入参数methods来指定使用的请求方法,该参数会以列表形式接收一种或多种请求方法。在HTTP规范中,定义了一组常用的请求方法:GET和POST
注:在Flask程序的视图函数中,默认的请求方式为GET
GET
•通常用于请求服务器上的资源,例如网页、图片、视频等。
•通过URL的查询字符串(query string)传递参数,参数会显示在URL中,可以被书签收藏,也可以被缓存。
•数据限制:由于参数是附加在URL上的,所以传输的数据量有限制,一般不能超过几千个字符。
•安全性:GET请求的参数在URL中可见,因此不适合传输敏感信息,如密码等。
#在视图函数login()上方通过装饰器route()注册路由,并显式指定请求方法为GET
@app.route('/login', methods=['GET'])
def login():
pass
POST
•通常用于向服务器提交数据,例如表单提交、上传文件等。
•通过HTTP请求的消息体传递参数,参数不会显示在URL中,对于大量数据或敏感信息更为安全。
•数据限制:由于参数在消息体中,所以传输的数据量相对较大,一般没有特定的限制。
•安全性:POST请求相对于GET请求更为安全,适合传输敏感信息。
#在视图函数login()上方通过装饰器route()注册路由,并显式指定请求方法为GET和POST。
@app.route('/login', methods=['GET', 'POST'])
def login():
pass
补充:HTTP的九种请求方法:
1 GET 请求指定的页面信息,并返回实体主体。
2 HEAD 类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头
3 POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和 / 或已有资源的修改。
4 PUT 从客户端向服务器传送的数据取代指定的文档的内容。
5 DELETE 请求服务器删除指定的页面。
6 CONNECT HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。
7 OPTIONS 允许客户端查看服务器的性能。
8 TRACE 回显服务器收到的请求,主要用于测试或诊断。
9 PATCH 是对 PUT 方法的补充,用来对已知资源进行局部更新 。
最常用的还是 GET , POST
在Flask2.0及其之后的版本提供了指定部分请求方式的便捷函数,这些函数与请求方法的名称相同,且都是小写形式的。
•get():route()传递methods=["GET"]的快捷函数。
•post():route()传递methods=["POST"]的快捷函数。
•put():route()传递methods=["PUT"]的快捷函数。
•delete():route()传递methods=["DELETE"]的快捷函数。
•patch():route()传递methods=["PATCH"]的快捷函数。
@app.post('/login')
def login():
pass
上下文
Flask使用上下文临时保存程序运行过程中的一些信息。Flask中有两种上下文,分别是请求上下文和应用上下文,其中应用上下文是随着请求上下文产生而产生,随着请求上下文销毁而销毁。
Flask的请求上下文
Flask的请求上下文包括request对象和session对象,其中request对象封装了请求信息;session对象用于记录请求会话中的用户信息。
request
- request对象中提供了用于处理请求信息的常用属性
属性 | 说明 |
args | 获取URL中的请求参数 |
methods | 获取请求的HTTP方法 |
cookies | 获取包含Cookie名称和值的字典对象 |
data | 获取包含字符串形式的请求数据 |
form | 获取解析后的表单数据 |
values | 一个包含form和args全部内容的CombineMultiDict |
headers | 获取首部字段 |
user_agent | 获取浏览器标识信息 |
- request对象中提供了用于处理请求信息的常用方法
方法 | 说明 |
close() | 关闭当前请求 |
get_data() | 获取请求中的数据 |
get_json() | 作为JSON解析并返回数据 |
make_form_data_parse() | 创建表单数据解析器 |
session
- session对象提供了很多获取Cookie信息的方法
方法 | 说明 |
get(key) | 通过传入的key值,获取Cookie中对应的value值 |
pop(key) | 通过传入的key值,删除Cookie中对应的value值 |
items() | 将Cookie中的值以“key:value”形式返回 |
values() | 获取Cookie中所有的value值 |
clear() | 清空当前站点Cookie中的内容 |
keys() | 获取Cookie中所有的key值 |
update() | 接收一个字典,根据接收的字典更新或添加到Cookie中 |
Flask的应用上下文
Flask的应用上下文包括current_app对象和g对象,其中current_app对象表示当前激活的Flask应用程序实例;g对象表示程序的一个全局临时变量,我们可以通过g对象在一次请求调用的多个函数间传递一些数据,每次请求都会重设这个变量。
current_app对象
当Flask程序无法导入程序实例或程序中有多个程序实例时,为了能够快速区分当前请求的程序实例,此时可以使用current_app对象。
from flask import Flask, current_app # 导入current_app对象
app = Flask(__name__)
app.secret_key = 'Your_seccret_key&^52@!'
@app.route('/')
def index():
return f'{current_app.secret_key}'# 通过current_app对象获取密钥
if __name__ == '__main__':
app.run()
g对象
g对象存储了一次请求的所有用户信息,例如,用户的登录信息、数据库的连接信息等,在同一个请求中,如果后续的代码中需要用户登录信息或数据库连接信息都可以通过g对象获取。当请求完成之后,g对象便会销毁;当发送一个新的请求时,g对象也会随之生成。
#使用g对象模拟获取当前用户信息
from flask import Flask, g
app = Flask(__name__)
@app.route('/')
def get_user():
user_id = '001' # 设置用户id
user_name = 'flask' # 设置用户名称
g.user_id = user_id # 将用户id保存到g对象中
g.user_name = user_name # 将用户名称保存到g对象中
result = db_query()
return f'{result}'
def db_query():
user_id = g.user_id # 使用g对象获取用户id
user_name = g.user_name # 使用g对象获取用户名称
return f'{user_id}:{user_name}'
结果:
6.响应处理
(1)响应报文
在Flask程序中,浏览器发出的请求会触发相应的视图函数,并将视图函数的返回值作为响应体,之后生成完整的响应内容,即响应报文。响应报文主要由4个部分组成,分别是状态行、响应报头、空行以及响应体。
•状态行(Status Line):状态行是响应报文的第一行,用于表示响应的状态和版本。它包含了HTTP版本号、状态码和对应的状态信息。例如:HTTP/1.1 200 OK。这里的 "200" 是成功的状态码,表示请求已成功处理。
•响应报头(Response Headers):响应报头位于状态行之后,用于传递关于响应的附加信息。它包含了多个键值对,每个键值对由一个字段名和一个字段值组成,中间用冒号分隔。
响应报头有很多内容,通用报头、请求报头、响应报头、实体报头等
常见的响应报头:
Location:用于重定向接受者到一个新的位置,常用在更换域名的时候
Server:包含可服务器用来处理请求的系统信息,与User-Agent请求报头是相对应的
•空行(Blank Line):空行是状态行和响应报头之后的一行,用于分隔响应报头和响应体。它实际上是一个空的换行符。
•响应体(Response Body):响应体位于空行之后,用于存储服务器返回给客户端的实际数据。它可以是HTML文档、JSON数据、图片、文件等各种形式的数据。响应体的内容取决于服务器处理请求后返回的数据。
(2)Response类
Response类封装了响应报文的相关信息。如果希望在Flask程序中主动生成响应,一般可以通过Response类的构造方法或make_response()函数实现。
Response(response, status, headers, mimetype, content_type, direct_passthrough)
•response:可选参数,表示视图函数返回的响应体。
•status:可选参数,表示响应状态码。
•headers:可选参数,表示响应报头。
•mimetype:可选参数,表示响应体的MIME类型。
•content_type:可选参数,表示响应体的类型。
from flask import Flask, Response
app = Flask(__name__)
@app.route('/index')
def index():
# 使用Response类的构造方法生成响应对象,设置状态码为201,响应类型为text/html
resp = Response(response='Python&Flask',status=201, content_type='text/html;charset=utf-8')
return resp
if __name__ == '__main__':
app.run()
结果:
(3)make_response()函数
make_response()函数也用于生成响应,它可以接收str、bytes、dict和tuple共4种类型的参数,当参数的类型为tuple时,参数的值可以为(body, status, headers) 、(body, status)或 (body, headers)任意一种形式,其中body表示响应体,status表示状态码,headers表示响应报头,另外header的值可以是一个字典或(key,value)形式的元组。
from flask import Flask, make_response
app = Flask(__name__)
@app.route('/index')
def index():
res = make_response('Python&Flask123',201,
{'content-type':' text/html;charset=utf-8'})
return res
if __name__ == '__main__':
app.run()
结果:
7.URL反向解析
URL反向解析(URL Reverse Resolution)是指根据视图函数名称和参数生成对应的URL。在Web应用中,通常会定义一些路由(URL规则)来映射到不同的视图函数,当需要生成特定的URL时,可以使用URL反向解析功能。
URL反向解析的作用:
•避免硬编码(硬编码就是直接把URL全名写上去):使用反向解析可以避免在代码中硬编码URL。硬编码的URL在修改时容易出错,并且不利于代码重用和维护。
•如果应用中的URL规则发生变化,只需要修改路由配置,而不需要在所有使用该URL的地方手动修改URL字符串。
•通过反向解析,可以根据视图函数名称和参数生成对应的URL链接。这样,在模板中或者其他地方需要生成URL时,就可以直接调用反向解析函数生成相应的URL,而不需要手动拼接URL字符串。
flask.url_for模块中提供了URL反向解析的函数url_for(),该函数可以根据视图函数的名称获取对应的URL。
url_for(endpoint,values,_external,_scheme,_anchor,_method,**values)
•endpoint:必选参数,表示反向解析的端点(用于标记一个视图函数以及对应的URL规则)名称,默认值为视图函数名。
•values:可选参数,表示URL地址传递的参数。
•_external:可选参数,表示是否供程序外部使用,默认值为False,若为True,则返回绝对URL地址,例如,http://127.0.0.1:5000/hello/flask。
from flask import Flask, url_for
app = Flask(__name__)
@app.route('/hello/flask')
def greet():
return f"{url_for('greet')}" # 反向解析视图函数greet()对应的URL
if __name__ == '__main__':
app.run()
结果:
若URL规则中包含要传递的参数,则调用url_for()函数时需要将该参数以关键字参数形式传递:
from flask import Flask, url_for
app = Flask(__name__)
@app.route('/hello/<name>')
def greet(name):
return f"{url_for('greet',name=name)}"
if __name__ == '__main__':
app.run()
结果:
使用url_for()函数反向解析URL时,除了传递URL规则中的参数以外,还可以传递任何额外参数给URL地址的参数
from flask import Flask, url_for
app = Flask(__name__)
@app.route('/hello/<name>')
def greet(name):
# 将age=20添加到URL地址中
return f"{url_for('greet',name=name, age=20)}"
if __name__ == '__main__':
app.run()
结果:
8.页面重定向
页面重定向在Web程序中非常普遍,例如,当用户在电商网站购买商品时,电商网站若检测到用户还未曾登录,则会将当前页面重定向到登录页面。在Flask程序中,页面重定向功能可以通过redirect()函数实现。
redirect(location, code=302, Response=None)
•location:必选参数,表示重定向的URL地址。
•code:可选参数,表示重定向状态码,默认状态码为302。
•Response:可选参数,表示实例化响应时使用的Response类,若未指定默认使用的响应类为werkzeug.wrappers.Response。
当用户首次访问欢迎页面时,若session中还没有记录过这个用户名,则会将欢迎页面重定向到登录页面;当用户在登录页面输入用户名登录后,会将登录页面重定向到欢迎页面。
from flask import Flask, url_for, request, redirect, session
app = Flask(__name__)
app.secret_key = 'Your_secret_key&^52@!'
@app.route('/index')
def index():
if 'username' in session:
return f'你好:{session.get("username")}' #返回欢迎信息
return redirect(url_for("login")) # 页面重定向到登录页面
....
9.模块
在一般的 Web 程序里,访问一个地址通常会返回一个包含各类信息的 HTML 页面。因为我们的程序是动态的,页面中的某些信息需要根据不同的情况来进行调整,比如对登录和未登录用户显示不同的信息,所以页面需要在用户访问时根据程序逻辑动态生成。
我们把包含变量和运算逻辑的 HTML 或其他格式的文本叫做模板,执行这些变量替换和逻辑计算工作的过程被称为渲染,这个工作由模板渲染引擎——Jinja2 来完成。
- Jinja2除了允许在模板中使用变量之外,还允许在模板中使用过滤器、选择结构、控制结构等,以多种方式控制模板的输出。
- Flask已经自动安装了Jinja2,我们在Flask程序中可以直接使用Jinja2。
(1)创建模块
- 创建模板其实就是创建HTML文件。为了保证Flask程序能够加载到模板文件,我们需要在项目的根目录下新建一个templates文件夹,之后将程序中用到的所有模板文件存放到该文件夹中。
- templates是Flask预先定义好的模板文件夹名称,如果希望使用其他的文件夹名称,则可以在通过代码创建Flask类对象时为template_folder参数传入其他的文件夹名称。
为了使用Jinja2模板引擎渲染模板,flask库中提供了render_template()函数。
render_template(template_name_or_list, **context)
•template_name_or_list:必选参数,表示要加载的模板名称。
•**context:可选参数,表示向模板文件传递的参数,以关键字参数的形式进行传递。注意,关键字参数的名称必须与模板文件中的变量名称保持一致。
在项目根目录下新建templates文件夹,在该文件夹下创建模板文件index.html,并在index.html文件中编写HTML代码。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
{#一级标题#}
<h1>Hello Flask!</h1>
</body>
</html>
在项目中再创建一个app.py文件,并在该文件中先定义一个视图函数, 再在视图函数中渲染模板文件index.html。
from flask import Flask, render_template # 导入render_template
app = Flask(__name__)
@app.route('/index')
def index():
return render_template('index.html') # 渲染模板文件index.html
if __name__ == '__main__':
app.run()
结果:
(2)模块基础语法
在模板里,需要添加特定的定界符将 Jinja2 语句和变量标记出来,下面是三种常用的定界符:
{ { ... }} 用来标记变量。
{% ... %} 用来标记语句,比如 if 语句,for 语句等。
{# ... #} 用来写注释。
{ { ... }}
- 模板变量是一种特殊的占位符,它用于标识模板中会动态变化的数据,当模板被渲染时,模板引擎将模板中的变量替换为由视图函数传递的真实数据。
{ {variable}}
- 上述格式中,variable表示模板变量的名称,变量名称应与视图函数中传递的关键字参数的名称相同。模板变量的命名规则与Python变量的命名规则相同。
Jinja2能够识别所有类型的变量,例如,列表、字典和对象等。
{ { info[3] }} # info是列表,获取列表中索引为3的数据
{ { info[username] }} # info是字典,获取字典中键为username的数据
{ { info.items() }} # info是对象,获取对象调用items()方法返回的数据
在app.py文件的视图函数index()中定义一个变量,之后将该变量传入render_template()函数中。
@app.route('/index')
def index():
name = 'World'
return render_template('index.html', name=name)
#在index文件中通过{
{}}传入该变量
<!DOCTYPE html>
<html>
<head>
<title>Index Page</title>
</head>
<body>
<h1>Hello, {
{ name }}!</h1>
</body>
</html>
{% ... %}
{% for hobby in hobbies %}
<li>{ { hobby }}</li>
{% endfor %}
举例:
<!DOCTYPE html>
<html>
<head>
<title>{
{ title }}</title>
</head>
<body>
<h1>{
{ greeting }}, {
{ name }}!</h1>
{% if age >= 18 %}
<p>You are an adult.</p>
{% else %}
<p>You are a minor.</p>
{% endif %}
<ul>
{% for hobby in hobbies %}
<li>{
{ hobby }}</li>
{% endfor %}
</ul>
{# This is a comment. #}
</body>
</html>
(3)过滤器
在Jinja2中,过滤器是用于修改或过滤模板变量值的特殊函数,使用过滤器可以获取更精确的数据。
{ { variable|filter(parameter) }}
variable表示变量的名称,filter(parameter)表示使用的过滤器,其中parameter表示传递给过滤器的参数。如果没有任何参数传给过滤器,则括号可以省略。一个模板变量可以使用多个过滤器,多个过滤器之间使用竖线分隔。
内置过滤器
Jinja2提供了许多内置过滤器,也可自定义过滤器,常用的内置过滤器如下:
过滤器 | 说明 |
abs() | 返回给定参数的绝对值 |
random() | 返回给定列表中的一个随机元素 |
safe() | 将变量值标记为安全,保证渲染时不进行转义 |
tojson() | 将给定参数序列化为JSON字符串 |
escape() | 会将<、>等特殊符号转义成HTML中的符号,使其成为普通字符串,避免渲染 |
length() | 返回变量值的长度 |
sort() | 对变量保存的数据进行排序,该函数内部调用的是Python的sorted()函数 |
Jinja2字段
字段 | 说明 |
join() | 使用指定符号将字符串中的字符进行拼接,默认符号为空字符串 |
int() | 将值转换为整数,如果转换不起作用,返回0 |
float() | 将值转换为浮点数,如果转换不起作用,返回0.0 |
capitalize() | 将变量值的首字母改为大写字母,其余字母改为小写字母 |
trim() | 清除变量值前后的空格 |
upper() | 将变量值转换为大写字母 |
举例:
join()
{% set numbers = [1, 2, 3, 4, 5] %}
{ { numbers|join('-') }}结果:
1-2-3-4-5
。int
{% set number_str = "123" %}{% set number_int = number_str|int %}
在app.py文件中,定义视图函数use_of_filters()以及触发该函数的URL规则/filters,在视图函数use_of_filters()中向模板传递不同类型的数据。
@app.route('/filters')
def use_of_filters():
num = -2.3
li = [2, 1, 5, 6, 7, 4, 4]
string = 'flask'
return render_template('filters.html', num=num, li=li, string=string)
在templates文件夹中新建filters.html文件,在该文件中对定义的模板变量使用过滤器修改或过滤变量值。
<!DOCTYPE html>
<html>
<head>
<title>Jinja2 Filter Example</title>
<body>
{#返回变量num的绝对值#}
<h4>绝对值:{
{ num|abs }}</h4>
{#将变量num转换为整型#}
<h4>转换为整型:{
{ num|int }}</h4>
{#返回变量li中随机的一个元素#}
<h4>获取随机元素:{
{ li|random }}</h4>
{#返回变量li的长度#}
<h4>获取列表长度:{
{ li|length }}</h4>
</body>
</head>
</html>
结果:
(4)选择结构
Jinja2支持选择结构。Jinja2提供了if、elif、else、endif,其中if、elif、else与Python关键字if、elif、else的含义相同,endif用于标识选择结构的末尾。
#注意的是,选择结构必须以{% endif %}结尾。
{% if 条件语句1 %}
语句1
{% elif 条件语句2 %}
语句2
……
{% else %}
语句n
{% endif %}
示例:
#app.py增加URL规则
@app.route('/query-score/<int:score>')
def query_score(score):
return render_template('select_struct.html',score=score)
#templates文件夹新建模板文件select_struct.html
<!DOCTYPE html>
<html>
<head>
<title>score</title>
<body>
{% if score >= 85%}
优秀
{% elif 75 <= score < 85%}
良好
{% elif 60 <= socre < 75%}
中等
{% else %}
差
{% endif %}
</body>
</head>
</html>
结果:
(5)循环结构
Jinja2还支持循环结构,其作用是循环遍历变量中的每个元素,以便在模板文件中使用这些元素。Jinja2中循环结构与Python中的for语句用法相似。
#for、endfor均使用{% %}进行包裹,其中for标识循环结构的起始位置,endfor标识循环结构的结束位置
#且两者都不能省略。
{% for 临时变量 in 变量 %}
语句
{% endfor %}
示例:
#app.py增加URL规则触发视图函数goods()
@app.route('/goods')
def goods():
goods_name = ['洗碗机','电饭锅','电烤箱','电磁灶','微波炉']
return render_template('loop_struct.html', goods_name=goods_name)
#在templates文件夹中新建模板文件loop_struct.html
<!DOCTYPE html>
<html>
<head>
<title>goods_list</title>
<body>
{% for good in goods_name %}
<h4>{
{ good }}</h4>
{% endfor %}
</body>
</head>
</html>
结果:
10.消息闪现
Flask提供了向用户反馈信息的方式——消息闪现。Flask中通过在视图函数中使用flash()函数实现消息闪现的效果,不过flash()函数执行后不会立即在浏览器页面中弹出一条消息,而是需要在模板中通过get_flashed_messages()函数获取消息,并将其显示到页面中。
(1)flash()函数
flash()函数通过flask.flash导入使用,用于发送消息
flash(message, category='message')
•message:必选参数,发送闪现的消息。
•category:可选参数,消息的类别。该参数支持4种取值,分别是message、error、info和warning,其中message是默认值,表示任何类型的消息;error表示错误的消息;info表示信息消息;warning表示警告消息。
(2)get_flashed_messages()函数
get_flashed_messages()函数是一个全局函数,可在模板的任意位置调用。
get_flashed_messages(with_categories=False , category_filter=())
•with_categories:可选参数,表示是否同时返回消息与消息类别,若设置为True,则会以元组形式返回消息和消息类别;若设置为False,则只会返回消息。
•category_filter:可选参数,表示只返回与消息类别一致的消息。
flash()函数会将发送的消息存储到session中,因此我们需要在程序中设置secret_key。
示例:
(1)在app.py文件中定义视图函数home_page(),该函数用于判断用户的登录状态。
from flask import Flask, render_template
from flask import flash, redirect, session, request, url_for
app.secret_key = 'Your_secret_key&^52@!' # 设置secret_key
@app.route('/home')
def home_page():
username = session.get('username')
# 判断session是否存储username的数据
if 'username' in session:
return render_template('home_page.html', username=username)
return redirect(url_for('login')) # 重定向到login页面
(2)在app.py文件中定义视图函数login(),获取用户在login页面输入的用户名和密码,如果用户输入错误,则通过消息闪现机制反馈给用户,反之将用户名和密码保存到session中,并将页面重定到home页面。
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
if request.form['username'] != 'admin' or \
request.form['password'] != '123':
flash('用户名或密码错误', category='error')
else:
session['username'] = request.form['username']
session['password'] = request.form['password']
flash('恭喜您,登录成功', category='info')
return redirect(url_for('home_page'))
return render_template('login.html')
(3)在templates文件夹中新建模板文件home_page.html,该模板文件用于展示home页面以及用户登录成功的消息。
<body>
<h2>主页</h2>
{% for message in get_flashed_messages(category_filter = ('info')) %}
<span>{
{ message }}</span>
{% endfor %}
<p>欢迎用户:{
{ username }}</p>
</body>
(4)在templates文件夹中新建模板文件login.html,该模板文件用于展示login页面以及登录失败的消息。
<body>
<h2>用户登录</h2>
{% for message in get_flashed_messages(category_filter = ('error')) %}
<p class="error" style="color: red;">{
{ message }}</p>
{% endfor %}
<form action="" method="post" class="form">
<span>用户名:</span><br>
<input type="text" name="username"><br>
<span>密码:</span><br>
<input type="password" name="password"><br>
<p><input type="submit" value="登录"></p>
</form>
</body>
结果:
输入/home,跳转到登录页面
用户名或密码错误
登录成功
11.静态文件的加载
(1)在模块中引用图片文件
在Flask程序中,默认情况下静态文件都存储在与项目文件同级目录的static文件夹中,该文件夹需要由开发人员创建。
- 为了能够在模板文件中引用静态文件,需要使用url_for()函数解析静态文件的URL,静态文件的URL规则默认为/static/<path:filename>。
- url_for()函数需要接收两个参数,第1个参数表示端点名称,默认值为static;第2个参数filename表示静态文件的名称。
url_for('static', filename='test.png')
#以上代码解析的URL规则为/static/test.png
在模板中若要引用图片文件,可以在定义<img>标签时通过src属性规定显示图像的URL,该URL是调用url_for()函数解析静态文件的URL。
<img src="{ { url_for('static', filename='test.png') }}">
示例:
(1)在项目的根目录下新建一个static文件夹,在static文件夹中导入图片文件flask.png;在templates目录下新建一个模板文件base.html,之后在模板文件base.html中引用图片文件flask.png。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<p>Flask-Logo图片</p>
{#引用flask.png#}
<img src="{
{ url_for('static',filename='flask.png') }}">
</body>
</html>
(2)在app.py文件中定义视图函数load_staticfile()以及触发该函数的URL规则/static-file,在该函数中渲染模板文件base.html。
@app.route('/static-file')
def load_staticfile():
return render_template('base.html')
结果:
(2)在模块中引用css文件
在模板中若要引用CSS文件,可以在定义<link>标签时通过src属性规定当前模板与CSS文件之间的关系,src属性的值为stylesheet,表示样式表;通过href属性规定被链接文档的URL,该URL是调用url_for()函数解析静态文件的URL。
<link rel="stylesheet" href="{ { url_for('static',filename='test.css') }}">
示例:
(1)新建一个CSS文件Italics.css
p{font-style:italic}
(2) 在项目的static目录中导入CSS文件Italics.css,之后在模板文件base.html中引用CSS文件Italics.css。(其他部分与上例相同)
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="{
{ url_for('static',filename='Italics.css') }}">
</head>
总体示例(较简单)
链接:https://pan.baidu.com/s/1U8yEFG6bX-NXFFjPa__Rzg
提取码:yb9v
之后深入学习会继续更新!