什么是Web Framework
Web Application Framework(Web应用程序框架)或简单的Web Framework(Web框架)表示一个库和模块的集合,使Web应用程序开发人员能够编写应用程序,而不必担心协议,线程管理等低级细节。
什么是Flask
Flask是一个用Python编写的Web应用程序框架。 它由 Armin Ronacher 开发,他领导一个名为Pocco的国际Python爱好者团队。 Flask基于Werkzeug WSGI工具包和Jinja2模板引擎。两者都是Pocco项目。
WSGI
Web Server Gateway Interface(Web服务器网关接口,WSGI)已被用作Python Web应用程序开发的标准。 WSGI是Web服务器和Web应用程序之间通用接口的规范。
Werkzeug
它是一个WSGI工具包,它实现了请求,响应对象和实用函数。 这使得能够在其上构建web框架。 Flask框架使用Werkzeug作为其基础之一。
jinja2
jinja2是Python的一个流行的模板引擎。Web模板系统将模板与特定数据源组合以呈现动态网页。
Flask通常被称为微框架。 它旨在保持应用程序的核心简单且可扩展。Flask没有用于数据库处理的内置抽象层,也没有形成验证支持。相反,Flask支持扩展以向应用程序添加此类功能。一些受欢迎的Flask扩展将在本教程后续章节进行讨论。
Flask安装条件
安装Flask通常需要Python 2.6或更高版本。虽然Flask及其依赖项适用于Python 3(Python 3.3以上版本),但是许多Flask扩展不能正确支持它。因此,建议在Python 2.7上安装Flask。
为开发环境安装virtualenv
virtualenv是一个虚拟的Python环境构建器。它可以帮助用户并行创建多个Python环境。 因此,它可以避免不同版本的库之间的兼容性问题。
以下命令用于安装virtualenv:
pip install virtualenv
此命令需要管理员权限。您可以在Linux / Mac OS上的 pip 之前添加 sudo 。如果您使用的是Windows,请以管理员身份登录。在Ubuntu上, virtualenv可以使用它的包管理器安装。
Sudo apt-get install virtualenv
安装后,将在文件夹中创建新的虚拟环境。
mkdir newproj
cd newproj
python -m venv newproj
要在 Linux / OS X 上激活相应的环境,请使用以下命令:
venv/bin/activate
要在 Windows 上激活相应的环境,可以使用以下命令:
venv\scripts\activate
我们现在准备在这个环境中安装Flask:
pip install Flask
上述命令可以直接运行,不需要系统范围安装的虚拟环境。
Hello Word程序
首选在项目中导入Flask模块。 Flask类的一个对象是我们的WSGI应用程序。
Flask构造函数使用当前模块(__name __)的名称作为参数。
Flask类的route()函数是一个装饰器,它告诉应用程序哪个URL应该调用相关的函数。
# -*- coding: utf-8 -*-
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "hello word"
if __name__ == "__main__":
app.run(host='0.0.0.0')
在上面的示例中,'/ ' URL与hello_world()函数绑定。因此,当在浏览器中打开web服务器的主页时,将呈现该函数的输出。
运行并访问页面
app.run()就相当于在命令行中执行flask run操作,flask自动启动自己安装的web服务
app.route()
@app.route(rule, options)
app.run()
Flask类的run()方法在本地开发服务器上运行应用程序,run()方法有4个参数可以选择
app.run(host, port, debug, options)
DEBUG及setting.py
if __name__ == "__main__":
app.run(host='0.0.0.0', debug=True)
app.config['ENV'] = 'development'
app.config['DEBUG'] = True
# settings.py
ENV = 'development'
DEBUG = True
# app.py
import sttings
app.config.from_object(settings)
app.run()方法参数表
Flask路由访问
现代Web框架使用路由技术来帮助用户记住应用程序URL。可以直接访问所需的页面,而无需从主页导航。
Flask中的route()装饰器用于将URL绑定到函数。例如:
from flask import Flask
app = Flask(__name__)
@app.route("/hello")
def hello():
return "hello, Word111111111"
if __name__ == '__main__':
app.run(debug=True)
在这里,URL '/ hello' 规则绑定到hello_world()函数。 因此,如果用户访问http:// localhost:5000 / hello URL,hello_world()函数的输出将在浏览器中呈现。
request(请求)和response(响应)
add_rul_rule()路由绑定
application对象的add_url_rule()函数也可用于将URL与函数绑定,如同使用app.route()。
装饰器的目的也可以由以下表示:
from flask import Flask
app = Flask(__name__)
def hello():
return "hello, Word111111111"
if __name__ == '__main__':
# 等效于@app.route('/hello'),因为app.route底层实际就是add_url_rule方法进行实现
app.add_url_rule('/', 'hello', hello)
app.run(debug=True)
通过向规则参数添加变量部分,可以动态构建URL。此变量部分标记为
在以下示例中,route()装饰器的规则参数包含附加到URL '/hello' 的
from markupsafe import escape
from flask import Flask
app = Flask(__name__)
"""
访问:http://127.0.0.1:5000/hello/xiaochen
输出:Hello xiaochen!
最后一个/后面的内容作为参数传递给前一个URL页面
"""
@app.route('/hello/')
def hello_name(name):
return 'Hello %s!' % name
if __name__ == '__main__':
app.run()
变量规则支持的类型
除了默认字符串变量部分之外,还可以使用以下转换器构建规则:
示例代码
from markupsafe import escape
from flask import Flask
app = Flask(__name__)
@app.route('/user/')
def show_user_profile(username):
# show the user profile for that user
return 'User %s' % escape(username)
"""
除了字符串,还可以传入int(整数)、float(浮点数)、path(带/分隔符的路径)
见show_post、show_float、show_subpath三个方法展示结果
"""
@app.route('/post/')
def show_post(post_id):
# show the post with the given id, the id is an integer
return 'Post Number %d' % post_id
@app.route('/float/')
def show_float(float_num):
return 'Float Number %f' % float_num
@app.route('/path/')
def show_subpath(subpath):
# show the subpath after /path/
return 'Subpath %s' % escape(subpath)
if __name__ == '__main__':
print(show_user_profile(username='yangxiaochen'))
print(show_post(post_id=1))
print(show_subpath(subpath='/project'))
app.run()
url_for()构造URL
url_for()函数对于动态构建特定函数的URL非常有用。该函数接受函数的名称作为第一个参数,以及一个或多个关键字参数,每个参数对应于URL的变量部分。
from flask import Flask, redirect, url_for
app = Flask(__name__)
"""
访问:http://127.0.0.1:5000/admin
输出:Hello Admin
"""
@app.route('/admin')
def hello_admin():
return 'Hello Admin'
"""
访问:http://127.0.0.1:5000/guest/xiaochen
输出:Hello xiaochen as Guest
"""
@app.route('/guest/')
def hello_guest(guest):
return 'Hello %s as Guest' % guest
"""
访问:http://127.0.0.1:5000/user/admin
自动重定向至 http://127.0.0.1:5000/admin
输出:Hello Admin
访问:http://127.0.0.1:5000/user/xiaochen
自动重定向至 http://127.0.0.1:5000/guest/xiaochen
输出:Hello xiaochen as Guest
"""
@app.route('/user/')
def hello_user(name):
if name =='admin':
return redirect(url_for('hello_admin'))
else:
return redirect(url_for('hello_guest',guest = name))
if __name__ == '__main__':
app.run(debug = True)
User()函数检查接收的参数是否与'admin'匹配。如果匹配,则使用url_for()将应用程序重定向到hello_admin()函数,否则重定向到将接收的参数作为guest参数传递给它的hello_guest()函数。
打开浏览器并输入URL - http://localhost:5000/user/admin
在浏览器中输入以下URL - http://localhost:5000/user/mvl
Response对象返回数据类型
settings.py
ENV = 'development'
DEBUG = True
app.py
# -*- coding: utf-8 -*-
import test
from flask import Flask, redirect, url_for, Response, make_response
import settings
app = Flask(__name__)
app.config.from_object(settings)
@app.route('/index1')
def index1():
return '返回字符串类型
'
@app.route('/index2')
def index2():
return {'a': 'beijing', 'b': 'shanghai', 'c': 'cehngdu'}
@app.route('/index3')
def index3():
return '元组类型', 200
@app.route('/index4')
def index4():
response = Response('通过Response返回HTML类型
')
print(response.content_type)
print(response.headers)
print(response.status_code)
print(response.status)
return Response('通过Response返回HTML类型
')
if __name__ == '__main__':
app.run()
Http协议是万维网中数据通信的基础。在该协议中定义了从指定URL检索数据的不同方法。
下表总结了不同的http方法:
默认情况下,Flask路由响应GET请求。但是,可以通过为route()装饰器提供方法参数来更改此首选项:、
# ending=utf-8
from flask import Flask, redirect, url_for, request
app = Flask(__name__)
"""
序号 方法与描述
1、GET:以未加密的形式将数据发送到服务器。最常见的方法。
2、HEAD:和GET方法相同,但没有响应体。
3、POST:用于将HTML表单数据发送到服务器。POST方法接收的数据不由服务器缓存。
4、PUT:用上传的内容替换目标资源的所有当前表示。
5、DELETE:删除由URL给出的目标资源的所有当前表示。
"""
"""
默认情况下,Flask路由响应GET请求。但是,可以通过为route()装饰器提供方法参数来更改此首选项。
login()方法配合login.html文件测试post/get访问:
login方法Flask路由响应POST、GET请求
当login.html中method = "post"时,访问login.html并提交表单得到返回:
这是"POST"方法访问得到页面,提交内容:test
login.html中method = "get"时,访问login.html并提交表单得到返回:
这是方法"GET"访问得到页面,提交内容:test
"""
@app.route('/success/,')
def success(function, content):
return '这是"{}"方法访问得到页面,提交内容:{}'.format(function, content)
"""判断请求类型,并将请求类型、表单内容通过url_for转发至/success进行展示"""
@app.route('/login', methods=['POST', 'GET'])
def login():
if request.method == 'POST':
text = request.form['nm']
return redirect(url_for('success', function='POST', content=text))
else:
text = request.args.get('nm')
return redirect(url_for('success', function='GET', content=text))
if __name__ == '__main__':
app.run(debug=True)
在大型应用中,把业务逻辑和表现内容放在一起,会增加代码的复杂度和维护成本.
使用模板的好处
在项目下创建 templates 文件夹,用于存放所有模板文件,并在目录下创建对应模板文件 html 文件
Flask模板-基础.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('Flask模板-基础.html')
if __name__ == '__main__':
app.run()
Flask模板-基础.html
Title
我的模板html内容
访问结果:
Flask模板-变量.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
# 往模板中传入的数据
my_str = 'Hello Word'
my_int = 10
my_array = [3, 4, 2, 1, 7, 9]
my_dict = {
'name': 'xiaoming',
'age': 18
}
return render_template('Flask模板-变量.html',
my_str=my_str,
my_int=my_int,
my_array=my_array,
my_dict=my_dict
)
if __name__ == '__main__':
app.run()
Flask模板-变量.html
Title
我的模板html内容
{{ my_str }}
{{ my_int }}
{{ my_array }}
{{ my_dict }}
访问结果:
Flask模板-示例.py
from flask import Flask, render_template
app = Flask(__name__)
"""
html文件作为模板结构固定,使用变量进行占位,使用rander_template传入变量进行渲染
类似于format函数,通过key=value的方式传入
"""
@app.route('/')
def index():
# 预先定义好将要传入html模板的内容
my_int = 18
my_str = 'curry'
my_list = [1, 5, 4, 3, 2]
my_dict = {
'name': 'durant',
'age': 28
}
# render_template方法:渲染模板
# 参数1: 模板名称 参数n: 传到模板里的数据
# return方法可以返回到浏览器中进行访问
res = render_template('Flask模板-示例.html',
my_int=my_int,
my_str=my_str,
my_list=my_list,
my_dict=my_dict)
return res
if __name__ == '__main__':
app.run(debug=True)
Flask模板-示例.html
Title
我是模板
{{ my_int }}
{{ my_str }}
{{ my_list }}
{{ my_dict }}
模板的list数据获取
{{ my_list[0] }}
{{ my_list.1 }}
字典数据获取
{{ my_dict['name'] }}
{{ my_dict.age }}
算术运算
{{ my_list.0 + 10 }}
{{ my_list[0] + my_list.1 }}
访问结果:
Web应用程序通常需要静态文件,例如javascript文件或支持网页显示的CSS文件。通常,配置Web服务器并为您提供这些服务,但在开发过程中,这些文件是从您的包或模块旁边的static文件夹中提供,它将在应用程序的/static中提供。
在下面的示例中,在index.html中的HTML按钮的OnClick事件上调用hello.js中定义的javascript函数,该函数在Flask应用程序的“/”URL上呈现。
Flask静态文件.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def index():
return render_template("index.html")
if __name__ == '__main__':
app.run(debug = True)
index.html
heloo.js
function sayHello() {
alert("Hello World")
}
访问结果:
来自客户端网页的数据作为全局请求对象发送到服务器。为了处理请求数据,应该从Flask模块导入。
Request对象的重要属性如下所列:
Request对象方法
# -*- coding: utf-8 -*-
from flask import Flask, redirect, url_for, request
import settings
app = Flask(__name__)
app.config.from_object(settings)
@app.route('/index')
def index():
print(request.headers, '\n')
print(request.path, '\n')
print(request.full_path, '\n')
print(request.base_url, '\n')
print(request.url, '\n')
return 'Flask Request对象方法'
app.run()
request.args.get() get访问取值
request.form.get() post访问取值
示例
我们已经看到,可以在 URL 规则中指定 http 方法。触发函数接收的 Form 数据可以以字典对象的形式收集它并将其转发到模板以在相应的网页上呈现它。
在以下示例中,'/' URL 会呈现具有表单的网页(student.html)。填入的数据会发布到触发 result() 函数的 '/result' URL。
result() 函数收集字典对象中的 request.form 中存在的表单数据,并将其发送给 result.html。
该模板动态呈现表单数据的 HTML 表格。
文件结构:
main.py
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/')
def student():
return render_template('student.html')
@app.route('/result',methods = ['POST', 'GET'])
def result():
# 获取当前请求方法
if request.method == 'POST':
# 获取字典对象,包含表单参数及其值的键值对信息
result = request.form
return render_template("result.html",result = result)
"""
运行程序,默认会访问'/'页面,即student.html表单页面。
student.html表单页面填写完毕,点击提交会将数据发送至'/result'页面
'/result'URL绑定的函数是result()
所以result方法可以通过request.method获取当前请求方法
当request.method == 'POST'时,通过request.form获取字典对象
最后通过render_template方法调用'result.html'并传入result字典进行渲染输出
"""
if __name__ == '__main__':
app.run(debug = True)
student.html
result.html
{% for key, value in result.items() %}
{{ key }}
{{ value }}
{% endfor %}
访问结果:
Cookie以文本文件的形式存储在客户端的计算机上。其目的是记住和跟踪与客户使用相关的数据,以获得更好的访问者体验和网站统计信息。
Request对象包含Cookie的属性。它是所有cookie变量及其对应值的字典对象,客户端已传输。除此之外,cookie还存储其网站的到期时间,路径和域名。
在Flask中,对cookie的处理步骤为:
"""
设置cookie,采用key, value, max_age的数据格式
默认有效期是临时cookie,浏览器关闭就失效
可以通过 max_age 设置有效期, 单位是秒
"""
@app.route("/set_cookies")
def set_cookie():
resp = make_response("success")
resp.set_cookie("cookie", "xiaochen",max_age=3600)
return resp
"""
获取cookie,通过request.cookies的方式, 返回的是一个字典,可以获取字典里的相应的值
"""
@app.route("/get_cookies")
def get_cookie():
cookie_1 = request.cookies.get("cookie")
return cookie_1
"""
这里的删除只是让cookie过期,并不是直接删除cookie
删除cookie,通过delete_cookie()的方式, 里面是cookie的名字
"""
@app.route("/delete_cookies")
def delete_cookie():
resp = make_response("del success")
# 指定设定'cookie'时指定的key
resp.delete_cookie("cookie")
return resp
完整代码:
from flask import Flask, make_response, request
app = Flask(__name__)
"""
设置cookie,采用key, value, max_age的数据格式
默认有效期是临时cookie,浏览器关闭就失效
可以通过 max_age 设置有效期, 单位是秒
"""
@app.route("/set_cookies")
def set_cookie():
resp = make_response("success")
resp.set_cookie("cookie", "xiaochen",max_age=3600)
return resp
"""
获取cookie,通过request.cookies的方式, 返回的是一个字典,可以获取字典里的相应的值
"""
@app.route("/get_cookies")
def get_cookie():
cookie_1 = request.cookies.get("cookie")
return cookie_1
"""
这里的删除只是让cookie过期,并不是直接删除cookie
删除cookie,通过delete_cookie()的方式, 里面是cookie的名字
"""
@app.route("/delete_cookies")
def delete_cookie():
resp = make_response("del success")
# 指定设定'cookie'时指定的key
resp.delete_cookie("cookie")
return resp
if __name__ == '__main__':
app.run(debug=True)
与Cookie不同,Session(会话)数据存储在服务器上。会话是客户端登录到服务器并注销服务器的时间间隔。需要在该会话中保存的数据会存储在服务器上的临时目录中。
为每个客户端的会话分配会话ID。会话数据存储在cookie的顶部,服务器以加密方式对其进行签名。对于此加密,Flask应用程序需要一个定义的SECRET_KEY。
定义secret_key
app.secret_key = 'fkdjsafjdkfdlkjfadskjfadskljdsfklj'
设置session会话变量
Session对象也是一个字典对象,包含会话变量和关联值的键值对。
Session[‘username’] = ’admin’
释放会话
session.pop('username', None)
完整演示程序及运行解读
# ending=utf-8
from flask import Flask, session, redirect, url_for, escape, request
"""Session对象也是一个字典对象,包含会话变量和关联值的键值对。"""
app = Flask(__name__)
"""定义secret_key,用于与服务器的会话加密方式签名"""
app.secret_key = 'fkdjsafjdkfdlkjfadskjfadskljdsfklj'
"""
访问首页,此时'username'键还尚未被添加至session字典对象中,因此返回visitor_status
即自动跳转至/login页面,由于此时并未提交数据,仍是get访问,因此返回login_form
待用户输入账户点击登陆之后数据返回至/login页面,判断访问方式为POST
则通过request.form获取html表单中定义的'username'键的值,赋值给session['username']
并通过url_for转发至index方法,index方法判断'username'存在因此返回login_status
login_status对登陆状态进行展示,并提供注销选项,点击注销选项后跳转至/logout页面
logout()方法回通过session.pop()将会话释放并重新跳转至index方法中
"""
@app.route('/')
def index():
login_status = "登录用户名是: {}
点击这里注销"
visitor_status = "您暂未登录
点击这里登录"
if 'username' in session:
username = session['username']
return login_status.format(username)
return visitor_status
"""用来提供登陆表单及将登陆表单中'username'值赋值给session并跳转至index方法"""
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
session['username'] = request.form['username']
return redirect(url_for('index'))
login_form = '''
'''
return login_form
"""用来释放会话并将页面返回至index"""
@app.route('/logout')
def logout():
# remove the username from the session if it is there
session.pop('username', None)
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(debug=True)
Flask类有一个redirect()函数。调用时,它返回一个响应对象,并将用户重定向到具有指定状态代码的另一个目标位置。
redirect()函数使用
Flask.redirect(location, statuscode, response)
在上述函数中:
状态代码标准化
以下状态代码已标准化:
重定向示例
from flask import Flask, redirect, url_for, render_template, request
"""调用redirect()函数时,它返回一个响应对象,并将用户重定向到具有指定状态代码的另一个目标位置。"""
# Initialize the Flask application
app = Flask(__name__)
"""
访问首页通过render_template方法渲染输出login.html
login.html页面提供一个表单,供用户输入账户信息
login()方法通过获取login.html访问方式提取'username'的值
如果访问方式为POST且'username'有值则重定向至/success
"""
@app.route('/')
def index():
return render_template('login.html')
@app.route('/login', methods=['POST', 'GET'])
def login():
if request.method == 'POST' and request.form['username'] == 'admin':
return redirect(url_for('success'))
return redirect(url_for('index'))
@app.route('/success')
def success():
return 'logged in successfully'
if __name__ == '__main__':
app.run(debug=True)
abort()方法返回错误代码
Flask.abort(code)
Code参数采用以下值之一:
返回错误代码示例
from flask import Flask, redirect, url_for, render_template, request, abort
app = Flask(__name__)
@app.route('/')
def index():
return render_template('log_in.html')
@app.route('/login',methods = ['POST', 'GET'])
def login():
if request.method == 'POST':
if request.form['username'] == 'admin' :
return redirect(url_for('success'))
else:
abort(401)
else:
return redirect(url_for('index'))
@app.route('/success')
def success():
return 'logged in successfully'
if __name__ == '__main__':
app.run(debug = True)
"""
当在路由后面再跟一个'/'的时候,此时不论访问/base还是/base/都会跳转至/base/
"""
@app.route('/base/')
def load_base():
return render_template('base.html')
在HTML文件中实现python语法
jinja2模板引擎可以帮助我们实现在HTML中支持python语法的动作,这样的HTML文件称为模板
@app.route('/')
def index():
return render_template('index.html', key1=value, key2=value')
模板变量使用:
{{ list.0 }} 同 {{ list[0] }}
{{ dict.key }} 同 {{ dict.get('key') }}
{{ obj.name }} 同 {{ 对象.属性 }}
模板的两种注释方法:
{# 这是模板注释方法,如此注释jinja2引擎便不会读取 #}
{!-- 这是html页面注释方法,如此注释浏览器就不会读取 --}
在模板中使用for循环
{% for i in list_obj %}
{% endfor %}
在模板中使用if判断
{% for i in list_obj %}
# 判断i的长度是否大于等于3
{% if i|length >= 3 %}
{% else %}
{% endif %}
{% endfor %}
或可以直接放在某个标签中使用
模板中循环可以使用的固定变量:
loop.index 获取当前变量索引,序号从1开始
loop.index0 获取当前变量索引,需要冲0开始
loop.revindex 倒序
loop.first 布尔类型 判断是否为第一行
loop.last 判断是否为最后一行
模板复用:
模板继承:多个模板具有完全相同的内容;多个模板具有相同的内容,但是内容中部分不一致;
标签:{% block 名字 %} {% endblock %}
模板继承的过程:
1、定义父模板,一般称为base.html
2、分析模板中变化的内容,对变化部分用block进行预留
3、样式和脚本需要提前预留
4、使用父模板{% extends '父模板名称' %};
找到对应的block填充