1.整体把握
(1)路飞学城 - RestAPI 前后端分离开发 DjangoVue.js - DRF DjangoRestFromwork - 线上商城的经验(2)智能玩具 - RestAPI 前后端分离开发 FlaskFlaskWeb框架 - Sanic Python asyncioWebSocket - 长连接 App开发 - Android + iOS MongoDB - NoSQL人工智能 - 技术应用机器学习 - Gensim自然语言处理 - NLP (3)自动化运维 - Django运维 -> 自动化
2.框架对比
Django :优点 - 大而全所有组件都是有组织内部开发高度定制化 教科书级别的框架 缺点 - 大到浪费资源,请求的时候需要的资源较高Flask ;优势 - 小而精,组件只有Session,第三方机构强烈支持Flask,非常多的三方组件 简单至极缺陷 - 由于三方组件的关系 稳定性相对较差 Flask-Session Tornado :优势 - 异步IO 非阻塞 原生WebSocket缺陷 - 组件 == 0 关于异步的不好理解 Debug难上加难 Sanic :优势 - 异步IO 非阻塞 原生WebSocket + 小而精,组件只有Session,第三方机构强烈支持Flask,非常多的三方组件缺陷 - 复杂度扩展知识: QPS = 请求每秒钟的次数 QPS == 10 时间片 cpu 工作一次的时间单位py 假线程 - 1个核心 真线程 - 4个核心 - 四个线程
首先,我们进入虚拟环境,virtual代表组件env代表环境,注意下图的选择内容
进入下图,看一下选择的内容
进入settings.py中,进行处理
安装一下上图中的flask.
装完之后的内容,见下图
3.Flask简单启动
三行启动Flaskfrom flask import Flaskapp = Flask(__name__)app.run()六行启动Flask Hellofrom flask import Flaskapp = Flask(__name__)@app.route("/")def index():return "hello"app.run()
成功访问,见下图
我们就使用"干净的环境变量就可以了"
六行搞定Hello
4.Flask响应
Response三贱客:1.HTTPResponse return "hello" 2.render return render_template("login.html")3.redircet return redircet("/login")Flask 封装4.send_file() return send_file("文件路径") 打开并返回文件内容 确定会在响应头中加入 Content-Type:文件格式 + Content-Length:文件大小(bytes)5.jsonify({k:v}) return jsonify({k:v})返回一个客户端可以识别的json格式字符串 确定会在响应头中加入 Content-Type:application/json
send_file
上图是返回的是文本文件的内容.也就是三行启动flask
我们查看到生成的是下图这样的html
我们可以返回文本文件当然可以访问二进制文件,什么是二进制文件?图片,视频,音频等等
同样可以处理二进制文件,音频,图片,视频
下面,我们从网上照一张图片"煎蛋"
保存,下图的图片
复制到下图的pycharm中
重启代码:
我们再看一下路由:
可能,不代表所有的都会支持.
这个时候,我们再看一下请求:
这个时候,我们可以访问视频了.
出现多个get_file是因为数据接收不完,所以出现了这个现象.
通过上面的三次测试,我们确定了,
下面介绍一下jsonify
首先导入jsonify
小的测试示例
运行,看一下结果:
下面,我们对比一下json&&jsonify的用法内容
运行:
注意这个content-Type响应的结果是text/html;charset=utf-8 结果是字符串
注意这个content-Type响应的结果是application/json
返回上边的结果的意义.
下面我们朝向ajax方向思考,先下载一个jQuery
右键,链接另存为,得到的结果见下图:
下面,我们写一个页面,写一下
下面我们看一下能不能加载成功:
上图,我们可以看到,已经加载成功了.
我们也可以直接拿到这个静态文件,见下图
我们再放一张图片在静态文件里边:
我们不用重启,直接访问的结果,见下图:
上边的背景也是黑色,也是jsonify
下面我们学习ajax的简写版只需要四个参数:
现在,我们需要向某个地方发送请求:
运行:得到下面的错误 405(METHOD NOT ALLOWED)
百度405错误,因为没有见过:
http的8种请求方式:
我们理解的是后端没有支持,因此,我们需要在后端加上方法,具体看下图:
这个时候,我们再次启动,得到下面的结果:
下面我们再写一个p标签
返回的结果1:
修改下面的内容:
重启,返回的结果2:
我们再次换成jsonify
重启,再运行,这个时候返回的结果见下图:
如果,我们访问的是json,下图是:
json显示的效果可能会好一些,但是这里边,我们需要找到的是json
这个时候,我们根本就没有办法通过字符串找到对应的msg
如果,我们序列化成jsonify,看一下msg
通过中间的某种协议沟通
0代表成功,1代表失败
如果前端没有写到,我们可以在jsonify写一个空值.
前端,我们通过alert返回
重启项目:
这个时候,出现了弹窗:
我们需要将需要的结果进行返回,这就是后端要干的事情,前端需要显示出来.
4.send_file() return send_file("文件路径") 打开并返回文件内容 确定会在响应头中加入 Content-Type:文件格式 + Content-Length:文件大小(bytes) 5.jsonify({k:v}) return jsonify({k:v})返回一个客户端可以识别的json格式字符串 确定会在响应头中加入 Content-Type:application/json
扩展 RestAPI-请求响应为json-请求支持的协议为http 8种请求
GET POST PUT DELETE OPTIONS//head trace
查 增 改 删
对应的CBV---原生 RestAPI
class
def post 增
def delete 删
def put 改
def get 查
def options 跨域请求
最后两个方法的作用,解决后端传递文件的不便利
jsonify解决json响应不成功的问题
注意,jsonify也可以修改头,Content-Type: laoayi/woaini
大前提,前端必须支持
5.Flask Request
比较特殊from flask import request #公共变量# 公共变量 被覆盖?不会(第四天)1.request.args 获取URL中的数据2.request.form 获取FormData中的数据3.request.values 获取args+form 知道就可以了4.request.data 流 # 获取请求体中的原始数据5.request.json 字典 # 请求头中带有Content-Type:application/json 将请求体中的数据反序列化到json中 但是在data中依然存储这原始数据bytes6.request.files 获取FormData中的文件数据 request.files.get("my_file")request.files.save(默认提交的文件名)记住:request.method
后端只能响应请求,所以先讲响应,再讲请求.
首先,我们导入request
我们看到源码中写的是公共变量:
运行:
访问根目录:
服务端成功,打印出GET
运行:
运行:
服务端得到下面的结果:
运行:前端返回66666
后端返回下图所示:
如何拿到,下图中的id=1 ???
运行,试一下前端的结果:
后端得到的结果:
request没有这个属性,我们可以打印一下args
运行:
上边符合字典的规则,我们可以通过get拿一下
顺便,因为重启太麻烦,我们可以配置一下那个自动重启
自动重启的配置方式一:
方式二:(注释掉上边的那个)
注意上边的访问参数:
上图是我们得到的结果
思考一下,能不能把字典进行序列化一下?
运行:
真的将结果序列化成字典了
再看一下类型
运行:
我们再通过转化成字典的方式,再拿值
运行:
得到的结果,成功拿到:
如果写成ages
报错:KeyError错误
从字典中取值的两种方式:索引取值,get方式取值,get取值可以默认是None,也可以设置默认值.索引取值的方式是keyerror
写一个form表单
运行:(将上边的s去掉)
输入123,点击"提交",结果报405的错误
这个时候,我们需要添加两种请求的方式:
运行:
这个时候,我们提交数据就不会报错了.
目前我们只支持两种请求:下面我们开始继续操作
测试一下是否有POST请求:
输入123,提交
得到下面的结果:
没有post
修改成下面的样子:
运行之后,输入345,点击"提交"
我们并没有得到任何数据:
还是没有数据
依然没有
得到上边的结果
通过上边,我们知道values优点特殊,下面我们在处理一下
运行:
访问下面的地址
提交之后得到的结果:
得到的结果:(服务端得到的结果:)
输入123,点击提交
这个时候,我们可以拿到123
将上边转化成字典
点击"提交"
点击"提交"
上边,我们得到的是"输入的内容4566"和链接中的键值
原来页面中的内容:
现在页面中的内容:
点击提交:
得到下面的结果:
也就是先序列化input里边的,再序列化action中的,同时后序列化的会覆盖先序列化的,
values.to_dict() #知道有这东西就行,一般不用,又不代表用
专业的叫法叫做FormData数据
4.Flask Request比较特殊from flask import request 公共变量# 公共变量 被覆盖?1.request.args 获取URL中的数据2.request.form 获取FormData中的数据3.request.values 获取args+form 知道就可以了4.request.data 流 # 获取请求体中的原始数据5.request.json 字典 # 请求头中带有Content-Type:application/json 将请求体中的数据反序列化到json中 但是在data中依然存储这原始数据bytes6.request.files 获取FormData中的文件数据 request.files.get("my_file")request.files.save(默认提交的文件名)记住:request.method 当前的请求方式
第四个和第五个,
第六,以后还会遇到
选择完之后:
点击提交:
这个时候,得到下面的结果
点击"提交"
拿到下图所示的结果:
依然,我们没有拿到任何结果:
我们改变一下请求的方式:
提交
enctype="multipart/form-data" #代表formdata的升级版
现在得到的数据是序列化之后的数据
思考,我们现在序列化这个files有意义吗?
点击"提交"
无意义,我们就拿出key
点击“提交",
得到上图的结果:
得到上边的结果没有意义,但是存储起来就有意义了
运行:
点击"提交"
在同一目录下得到这个数据
注意,再修改一下,新版本一定要写名字.
点击"提交",
得到上边的结果
不能修改文件格式.(可以改,但是修改一般没有什么意义)
直接刷新:
这样就将图片保存到静态文件里边;
提交:
这样,我们就得到上边的结果.
6.Jinja2(爸爸flask用的)-template(儿子django用的)
{{}} 引用 执行函数{%%} 逻辑代码
在做之前,我们先找点数据
添加一个函数
创建一个index.html页面:
我们下面对模板做一个备注
第一次写可能不是这样的,可能是Template Folder
在上边,我们选择"Jinja2",这样就不显示黄色下划线了,这样操作之后,我们就支持Jinja2
包括在python中不显示下划线和在html中jinja2的语法
下面我们从python的函数中传递数据到html中.
注意,我们传递的是stu,上图中多了一个逗号
启动,我们看下我们的数据
显然,我要的不是这样的效果:
我们可以通过字典进行取值.
下面是三种方式取数据
运行:得到下面的结果
django中只支持 点
下面我们在传递一个列表数据
运行:
我们可以想办法将它遍历出来
这个位置有点重名,但是作用域不同.
运行:
如果每组数据换个行,只需要加一个p标签就可以了
这样就可以换行了.
如果不想循环怎么办?一个一个吧
依然是可以拿数据的
运行:
运行:得到下面的结果
jinja2功能多了一些
这个时候,我们得到上边的结果.
得到下图所示的结果:
在表格中加上边界:
运行:
得到下面的结果:
上边有一个性别错误,下面我们进行处理
下面进行扩展一下:
{{}} 引用 执行函数{%%} 逻辑代码 if for macro
对比django中的simple_tag
引用函数
在前端执行函数,传参
下面我们进行升级,让所有的页面都能用这个函数
修改成全局模板之后,我们不在需要传递函数
现在,我们直接调用就可以了
这个时候,每个页面都可以用了
jinja2中的macro语句,相当于def,也就是定义函数
除了定义函数,我们还需要执行函数
这个时候,我们得到上边的结果
这个时候,得到上边的结果
也就是上边的宏指令
上边这个有点鸡肋的感觉.
只有django是template 高度定制化的东西
其他flask和tornado和sanic都是原生的东西,也就是jinja2
7.Session Flask中的Session flask原生自带的Session,不是第三方组件中的Session
from flask import sessionapp.secret_key = "序列化Session需要的字符串儿"在视图函数中session["key"] = "value"
我们通过request的源码找到session
点击进去,
上边的两行代码,特别的相似.
再创建一个login2页面:
上边我们进行了判断.
运行:
输入123
得到下面的界面:
很显然,上边不是我们需要的效果
运行:输入admin
提交之后,显示"错误"
我们使用正确的密码登录
得到 结果:
下面我们将输入的session,保存
点击登录,报下面的错误:
也就是说,在app里边设置一个secret_key
这个时候,我们再添加一行这样的信息.
再次运行:
输入密码,点击"登录"
这样,上边我们就登录成功了.
这样就代表我们我们session已经开启了.
我们设置一下,只要定向到index页面,我们就打印session["username"]里边的内容
再次运行:
点击"登录"
服务端也就打印出了这个内容.
session存放在哪个地方?内存中?不是,
这样我们就得到session的位置.存储在浏览器中.
session和cookie是什么,区别是什么?
通常我们解释的是session存放在服务端的键值对,cookie是存放在浏览器端的键值对.
在flask这里,我们在浏览器中,看到了session,三观改变了,我们看到的是序列化的session.
一切朝着最小化,精细化搞事情,朝着精简的方向搞事情.
flask连数据库都没有,为什么占用我服务端的资源存储客户端的没有用的资源,所以存储在客户端.想办法,将自己的状态自己保持,但是这个时候就不安全了.
我们是否能够拿到上边的资源在另一台机器上实现登录?答案是否定的.
session是有加密机制的.这里边存储的就是我们的数据
//eyJ1c2VybmFtZSI6IkFsZXhEU0IifQ.XK9VAg.JLrPbOZk5Urlxzh7mDimPFIE2Uo
//
这个时候,我们向这里边多添加几条数据,理论上会变长很多,下面看一下
再次运行:点击"登录"
//eyJ1c2VybmFtZSI6IkFsZXhEU0IifQ.XK9VAg.JLrPbOZk5Urlxzh7mDimPFIE2Uo
//.eJyrViotTi3KS8xNVbJScsxJrXAJdlLSgQsaYhU1wipqjCRaCwD6YRwn.XK9XlA.O10ASWENVes-Qtlep4vqZdHudhI
这个时候我们得到的结果只是长了一点点,再多也是只长一点点
也就是将一样的值进行了序列化了.所以我们看不出来了.
再次运行:
//eyJ1c2VybmFtZSI6IkFsZXhEU0IifQ.XK9VAg.JLrPbOZk5Urlxzh7mDimPFIE2Uo
//.eJyrViotTi3KS8xNVbJScsxJrXAJdlLSgQsaYhU1wipqjCRaCwD6YRwn.XK9XlA.O10ASWENVes-Qtlep4vqZdHudhI
//.eJyrViotTi3KS8xNVbJScsxJrXAJdlLSgQsaIkRjSs3MjSxiSs1NUpKRVBghqzA1TEzGUGGMrMLC0jwNqqIWAMSlJ7I.XK9Ycw.b4ls6NT-ebmqmxa1-LPhQgkpvNs
得到的结果是:session中一定存放的是key-value,注意安全只是相对的
也就是说加密和解密都需要上边我们设置的字符串.
app.secret_key="secret_key"
如果我们修改了这个字符串.
运行:
只是执行下面的页面得到的结果
这个时候session就无效了.
这里边携带了很多的信息,加密机制是个pass.
上边是一个装饰器
写这个装饰器的目的就是加上session
被装饰的函数一定在下面,
@classmethod 类方法装饰器
@property 属性装饰器
当然上边的存储字典是不行的,我们必须存储字符串
如果登陆成功,代表index函数中就有session了.
上边这种方式出不来数据,可能当时环境存在问题,再次调试的时候,可以得到相应的数据了
下边这种方式是可以出来数据的
alt+上 纵向选择
alt+enter 快速找包.