Flask入门
一、Flask框架的简介
Flask是当下流行的Web框架,它是用Python实现的。Flask显著的特点是:它是一个“微”框架。”微”意味着Flask旨在保持核心的简单,但同时又易于扩展。默认情况下,Flask 不包含数据库抽象层、表单验证,或是其它任何已有多种库可以胜任的功能。然而,Flask 支持用扩展来给应用添加这些功能。众多的扩展提供了数据库集成、表单验证、上传处理、各种各样的开放认证技术等功能。Flask的这些特性,使得它在Web开发方面变得非常流行。
二、MVC设计模式
一种软件设计典范,用一种业务逻辑,使数据,界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面与用户交互的同时,不需要重新编写业务逻辑。
MVC被独特的发展起来用于映射传统的输入,处理和输出功能在一个逻辑的图形化界面结构中
核心思想:解耦
优点:降低个模块之间的耦合性,方便变更,更容易重构代码,最大程度实现了代码的重用。
MVC(Model,View,Controller)
Model:用于封装与应用程序的业务逻辑相关的数据及对数据的处理方法,是Web应用程序中用于处理应用程序的数据逻辑部分,Model通常只提供功能性的接口,通过这些接口可以获取Model的所有功能。
View:负责数据的显示和呈现,View是对用户的直接输出。
Controller:负责从用户端收集用户的输入,可以看成提供View的反向功能,主要处理用户交互
三、python中MVT
MVT(Model,View,Templates)
Model:用于封装与应用程序的业务逻辑相关的数据及对数据的处理方法,是Web应用程序中用于处理应用程序的数据逻辑部分,Model通常只提供功能性的接口,通过这些接口可以获取Model的所有功能。
Templates:负责数据的显示和呈现,View是对用户的直接输出。
View:负责从用户端收集用户的输入,可以看成提供View的反向功能,主要处理用户交互
四、WEB架构
(1) B/S 浏览器->服务器
WEB网站
(2) C/S 客户端->服务器
五、Flask框架俩大核心
Werkzeug 和 Jinja2
Werkzeug:实现路由 调试 和 web服务器网关接口
Jinja2:实现了模板(是flask核心开发组成员开发的)
六、Flask的简单入门使用
(1) 安装
pip install flask
(2) 启动完整程序
实例:
from flask import Flask
#实例化flask类 传入必传参数 __name__ import_name
app = Flask(__name__)
# 添加路由
@app.route('/')
def index():
return 'Hello Flask'
# 运行
if __name__ == '__main__':
app.run()
注意:
假如在运行flask项目过程中 出现地址被占用 那也就是说 之前开启的服务并没有死掉 那么你可以去杀死进程 或者关闭编辑器 在或者更改一下端口号 这些都可以解决这个问题
端口不传 默认5000
访问:
http://127.0.0.1:5000/
(3) 路由地址
# 添加路由 装饰器 传参就是字符串
@app.route('/')
def index():
return 'Hello Flask'
访问:
主机:端口/
(4) 启动参数
参数 | 说明 |
---|---|
debug | 是否开启调试模式 默认为False 开启后自动加载代码 并进行如调试 |
threaded | 是否卡其多线程 默认不开启 |
port | 端口号 默认5000 |
host | 指定主机 默认127.0.0.1 |
app.run(host=‘0.0.0.0’,port=5001,debug=True,threaded=True)
当将主机设置为0.0.0.0 意味着可以使用IPV4或者127.0.0.1/localhost进行访问 如果不设置0.0.0.0 只能localhost/127.0.0.1进行访问
七、视图参数
(1) 无参路由
# 添加路由
@app.route('/')
def index():
return 'Hello Flask'
(2) 路由地址结尾/的实例
无/作为结尾
# 创建test路由
# 访问地址为 127.0.0.1:5000/test
@app.route('/test')
def test():
return '我是test路由地址'
访问:
http://127.0.0.1/test
有/作为结尾
# 创建test路由
@app.route('/test/')
def test():
return '我是test路由地址'
访问:
- http://127.0.0.1/test(多一个301的重定向)
- http://127.0.0.1/test/
(3) 带一个参数的路由地址
# 带一个参数的路由地址
# 访问:
# 127.0.0.1:5000/arg/lucky/
@app.route('/arg/<name>/')
def arg(name):
return '你好:'+name
访问:
- http://127.0.0.1:5000/arg/lucky/
(4) 带多个参数的路由地址
# 带多个参数的路由地址
# http://127.0.0.1:5000/args1/zhangsan/18/
# http://127.0.0.1:5000/args1/zhangsan_18/
@app.route('/args1/<name>/<age>/')
@app.route('/args1/<name>_<age>/')
def args1(name,age):
return 'name:{} age:{}'.format(name,age)
访问:
- http://127.0.0.1:5000/args1/zhangsan/18/
- http://127.0.0.1:5000/args1/zhangsan_18/
(5) 传参类型的限定
# 限定参数类型
# 默认参数类型为字符串
# 可以通过 int/float/path/string进行类型的限定 默认为string
# @app.route('/test/<arg>/') #默认为字符串
# @app.route('/test/<int:arg>/') #限定传参类型为整形 否则失败
# @app.route('/test/<float:arg>/') # 限定传参类型为浮点 否则失败
# @app.route('/test/<string:arg>/') # 传参不管什么类型 最终都为字符串
@app.route('/test/<path:arg>/') # 会把分隔符/认为是参数的一部分
def test(arg):
print(type(arg))
print(arg)
return '测试路由地址传参的类型'
访问:
- http://127.0.0.1:5000/lucky/
- http://127.0.0.1:5000/18/
- http://127.0.0.1:5000/1.1/
- http://127.0.0.1:5000/lucky/
- http://127.0.0.1:5000/lucky/18/man/
注意:
-
路由地址和视图函数可以不重名
-
return + 字符串的内容 目前所写的这种形势 只是为了进行简单的测试 那以后工作的时候 返回的都是渲染后的模板(html页面)
-
在定义路由地址的时候 如果结尾没有添加/作为结尾 那么在访问的时候 结尾也不能带/ 否则404访问不到
-
在定义路由地址的时候 如果结尾有/ 在访问的时候 路由地址可以有/也可以没有 都可以访问到 所以 创建路由地址的时候 建议都+/作为路由地址的结尾
-
参数的写法为 <参数的名称>
-
一个视图函数可以有多个路由地址
-
一个视图传递多个参数 使用路由地址的分隔符/进行分隔 或者使用参数_进行拼接
-
路由地址传递参数默认类型为字符串
-
可以通过int/string/float/path进行参数类型的限定
-
参数的限定格式为<限定符:参数名称>
八、重定向 redirect
作用:
可以通过访问的地址跳转到另外一个地址(试图函数)
导入:
from flask import redirect,url_for
要进行跳转的路由地址视图函数为
# 添加首页视图
@app.route('/')
def index():
return 'Hello Flask'
# 带参的视图函数
# http://127.0.0.1:5000/args/lucky/18/
@app.route('/arg/<name>/<age>/')
def args(name,age):
return '我叫:{} 我今年:{}岁了'.format(name,age)
(1) redirect使用实例:
作用:通过给定的路由地址进行跳转访问
# 测试redirect的使用
@app.route('/test_redirect/')
def test_redirect():
# return '测试重定向的视图函数'
# 重定向到首页
return redirect('/')
# 重定向到带参的视图函数 args 如果不给传递参数 则为404
# return redirect('/args/')
return redirect('/args/lucky/18/')
注意:
- redirect跳转其实就是将你在浏览器访问的那个路由地址5000后面的粘贴过来就可以了(或者是将代码中的路由地址粘贴到redirect中 如果存在参数的位置 替换成参数即可)
- 如果重定向的路由地址发生了改变 则重定向跳转失败(重定向的地址是写死的 也就是说不是通过代码动态生成的)
(2) url_for使用实例:
作用: 可以通过视图函数名称 动态生成路由地址 (也就是会根据视图函数来动态生成路由地址 不论路由地址如何更改 都可以动态生成)
# url_for的使用
@app.route('/test_url_for/')
def test_url_for():
# return '测试动态生成路由地址'
# 测试无参路由地址
return url_for('index')
# 测试带参路由地址的构造
return url_for('args',name='lucky',age=18)
(3) redirect 与 url_for 的组合使用
实例:
# redirect 与 url_for 的组合使用
@app.route('/redirect_url_for/')
def redirect_url_for():
# return 'redirect 与 url_for 的组合使用'
# return redirect(url_for('index'))
return redirect(url_for('args',name='lucky',age=18))
九、abort 终止
概述:
如果在视图函数处理过程中 出现了异常错误 可以使用abort函数 立即进行视图函数的终止
传参:
abort函数的传参为http标准的状态码 如 404/500 返回状态码对应的信息 如果传递的为http标准中不存在的状态码 则无任何实际意义
类似于python中的raise
导入:
from flask import abort
实例:
from flask import Flask,abort
# 测试abort函数的使用
@app.route('/test_abort/')
def test_abort():
print('我是上面的代码')
abort(500)
print('我是下面的代码')
return 'test_abort'
注意:
- abort如果给定的状态码不存在 则跑出flask异常的错误信息
- abort和raise 都会正常执行上面的代码 下面的代码不在执行
捕获抛出的状态码
from flask import render_template
# 捕获状态码(1.系统自己抛出的 2.手动人为抛出的)
# 参数为要捕获的状态码
@app.errorhandler(404)
def page_not_found(e):
# return '错误为:{}'.format(e)
# return e
# 渲染模板
return render_template('page_not_fonnd.html')
# 捕获500的状态码
@app.errorhandler(500)
def page_not_found(e):
# return '错误为:{}'.format(e)
# return e
# 渲染模板
return render_template('page_not_fonnd.html')
注意:
- 不光可以捕获人为抛出的状态码 还可以捕获系统抛出的
- 参数为你要捕获的状态码 如果想捕获多个 那么就多写几个捕获的装饰器就可以啦
十、请求 request
作用:
获取请求者所携带数据
概述:
浏览器发送到服务器的所有请求被flask接收以后 创建出request对象 request请求对象被用在视图函数中 获取请求的数据
使用:
from flask import request
request请求对象的属性
- url 获取完整的请求URL
- base_url 去掉get参数的url
- host_url 只有主机IP和端口号的url地址
- host 返回主机和端口
- path 请求的路由地址
- method 请求的方法的类型
- remote_add 请求客户端的IP地址
- args 获取get传参
- form 获取form表单post方法请求的数据
- files 文件上传
- headers 存储所有请求头信息
- cookies 获取存储cookie信息
- json 获取传递过来的json数据
请求地址
http://127.0.0.1:5000/test_request/?name=lucky&age=18
实例:
from flask import Flask,request
@app.route('/test_request/')
def test_request():
# print(request.url)
# print(request.base_url)
# print(request.host_url)
# print(request.host)
# print(request.path)
# print(request.method)
# print(request.remote_addr)
# 不建议这样
# print(request.args['name'])
# print(request.args['age'])
# 建议使用get方法
# print(request.args.get('xxx','default默认值'))
print(request.headers.get('User-Agent'))
return 'test_request'
如果获取get传递的多个参数 可以使用如下代码实现
print(request.args.getlist('name'))
print(request.args.getlist('name')[0])
print(request.args.getlist('name')[1])
请求地址:
http://127.0.0.1:5000/test_request/?name=lucky&name=18
十一、路由响应 response
请求对象是框架创建的 响应对象是由我们程序员创建的
(1) 一个简单的响应
# 构造一个简单的响应(携带状态码)
@app.route('/')
def index():
return 'index',404
(2) 通过make_response构造响应
需要导入:
from flask import make_response
@app.route('/make_response/')
def test_make_response():
res = make_response('我是make_response构造的响应',404)
return res
十二、会话控制cookie与session
概述:
我们的协议为http超文本传输协议 无状态协议 每一次的请求都是新的请求 所以通过cookie和session作为一个连续会话请求的状态的保持
cookie
简介流程图
第一次
客户端 -----》服务器
cookie
客户端《-----服务器
携带者cookie
客户端 -----》服务器
cookie值的存储
cookie的值存储在客户端浏览器上 明文存储不安全 客户端的浏览器会限制单个站点cookie的个数为20个 并且单个cookie的保存值的大小不能超过4k
(1) 设置cookie
格式:
response.set_cookie(key,value,max_age=None,expires=None)
key:键
value:值
max_age:过期时间 秒为单位
expires:以秒为单位的失效时间
实例:
# 设置cookie
@app.route('/set_cookie/')
def set_cookie():
# 构造响应
res = make_response('设置cookie')
# 设置cookie
res.set_cookie('name','lucky')
return res
设置成功后 可以在浏览器的网络进行点击查看 -->Response Headers
默认过期时间为 浏览会话结束时 也就是关闭浏览器
(2) 设置cookie并设置过期时间
实例:
#设置cookie并设置过期时间
@app.route('/set_cookie_lifetime/')
def set_cookie_lifetime():
res = make_response('设置cookie并设置过期时间')
# max_age 设置过期时间 给定的值为存活的秒数
res.set_cookie('name','lucky',max_age=20)
# 给定一个终止的时间戳
expires = time.time()+20
res.set_cookie('name','lucky',expires=expires)
return res
(3) 获取cookie
实例:
#获取cookie
@app.route('/get_cookie/')
def get_cookie():
return request.cookies.get('name','默认值')
(4) 删除cookie
实例:
#删除cookie
@app.route('/del_cookie/')
def del_cookie():
res = make_response('删除cookie')
# 删除key为name的cookie 第一种删除的方式
# res.delete_cookie('name')
# 第二种删除 重新设置 刚设置完就死掉了
res.set_cookie('name','',expires=0)
return res
session
概述:
session将数据存储在服务器端 给客户端cookie唯一的sessionID号 通过客户端请求携带着唯一的session_id 进行获取对应的数据
flask会将会话对象加密后存储在客户端的cookie中 因此必须要为应用实例的secret_key 属性配置一个加密种子 才能使用session
实例:
app.secret_key = '随机的字符串'
app.config['SECRET_KEY'] = '随机字符串'
导入:
from flask import session
实例导入与配置
from flask import Flask,session
app = Flask(__name__)
# 添加配置参数
app.config['SECRET_KEY'] = 'lucky is a good man'
(1) 设置session
实例:
from flask import Flask,session
# 设置session
@app.route('/set_session/')
def set_session():
# 设置session
session['name'] = 'lucky'
return '设置session'
默认存活时间为 浏览会话结束时 也就是关闭浏览器
(2) 设置session及过期时间
导入:
from datetime import timedelta
计算时间差值的累类参数都为时间
实例:
#设置session并设置过期时间
@app.route('/set_session_lifetime/')
def set_session_lifetime():
# 设置session持久化存储
session.permanent = True
app.permanent_session_lifetime = timedelta(minutes=3)
session['name'] = 'lucky'
return '设置session及过期时间'
(3) 获取session
实例:
#获取session
@app.route('/get_session/')
def get_session():
return 'name的值为:{}'.format(session.get('name','默认值'))
(4) 删除session
实例:
# 删除session
@app.route('/del_session/')
def del_session():
# 删除指定的key
# session.pop('name')
# 移除所有session 适用于网站退出登录 删除所有session会话
session.clear()
return '删除session'
cookie和session的区别
- cookie的数据存储在客户端浏览器上 session数据存储在服务器上
- cookie明文存储不安全 session比cookie更加安全
- session会在一定时间内保存数据在服务器上 当访问增多 会比较占用你服务器的性能 考虑到服务器的性能 可以将不重要的数据存储在客户端浏览器上 也就是cookie上
- 单个cookie保存的数据不能超过4k 很多浏览器会限制一个站点最多保存20个cookie
所以lucky老师建议:
将登录等重要的信息 存放在session中
其它信息如果需要保留 建议存放在cookie中
十三、flask-script扩展库
安装:
pip install flask-script
简介:
简单来说 就是一个flask终端运行解析器 因为在项目完成以后 最好不要更改任何代码 否则都会带来风险 所以借助扩展库实现启动 通过传递参数 完成不同的启动
使用:
from flask import Flask
from flask_script import Manager
app = Flask(__name__)
# 实例化终端运行解析器
manager = Manager(app)
...
if __name == '__main__':
manager.run()
optional arguments:
-?, --help show this help message and exit
-h HOST, --host HOST
-p PORT, --port PORT
–threaded
–processes PROCESSES
–passthrough-errors
-d, --debug enable the Werkzeug debugger (DO NOT use in production
code)
-D, --no-debug disable the Werkzeug debugger
-r, --reload monitor Python files for changes (not
100{‘option_strings’: [’-r’, ‘–reload’], ‘nargs’: 0,
‘const’: True, ‘metavar’: None, ‘default’: None,
‘type’: None, ‘required’: False, ‘prog’: ‘manage.py
runserver’, ‘container’: <argparse._ArgumentGroup
object at 0x7f7fbec11a58>, ‘help’: ‘monitor Python
files for changes (not 100% safe for production use)’,
‘dest’: ‘use_reloader’, ‘choices’: None}afe for
production use)
-R, --no-reload do not monitor Python files for changes
完整的访问参数为:
python3 manage.py runserver -h0.0.0.0 -p5001 -d -r
python manage.py runserver -d -r
十四、蓝本 blueprint
导入:
from flask import Blueprint
概述:
当我们的代码越来越复杂的时候 将所有的视图函数放在一个文件中 很明显是不合适的 如果能够根据功能模块进行划分 存储在不同的文件中 那么蓝本就是未解决此问题而存在的
使用实例:
蓝本文件 user.py
from flask import Blueprint # 导入蓝本
# 参数1 user
user = Blueprint('user',__name__)
# 登录的视图函数
@user.route('/login/')
def login():
return '登录'
# 注册的视图函数
@user.route('/register/')
def register():
return '注册'
manage.py
from flask import Flask
from flask_script import Manager
app = Flask(__name__)
manager = Manager(app)
@app.route('/')
def index():
return 'index'
# 测试重定向跳转的视图函数
@app.route('/test_redirect/')
def test_redirect():
return '测试重定向'
# 导入蓝本对象
from user import user
# 注册蓝本
# http://127.0.0.1:5000/login/
app.register_blueprint(user)
# 参数1为蓝本对象 参数2为访问蓝本路由的前缀 默认没有
# http://127.0.0.1:5000/user/login/
# app.register_blueprint(user,url_prefix='/user')
if __name__ == '__main__':
manager.run()
蓝本文件的重定向
实例:
# 测试重定向跳转的视图函数
@app.route('/test_redirect/')
def test_redirect():
# return '测试重定向'
# 从manage 重定向到user
# return redirect('/login/')
# 使用url_for 构造路由 错误的写法
# return url_for('login')
# 需要告诉url_for是哪一个蓝本文件的login视图函数
return url_for('user.login')
注意:
在构造蓝本文件路由地址的时候 需要告诉url_for是哪个蓝本文件的视图函数名称 否则构造失败