新篇章---flask---3
作者:互联网
目录
新篇章---flask---3
一 CBV
1.1 概念
参考django中的cbv和FBV,赫然发现,没啥区别. 框架的东西应该都是差不多的,,吧. CBV是(class base views) ,可以自定义属性方法.
rest API的话更建议使用CBV的方式.
导入方式,from flask.views import MethodView
,然后写app.add_url_rule('/login', endpoint=None, view_func=Login.as_view('/login')) #本来写的是login,但是经过测试又报了名字重复的错误
导入即可.
1.2 实例
from flask.views import MethodView
class Login(MethodView):
def get(self):
pass
print(Login.__module__)
print(Login.__class__)
app.add_url_rule('/login', endpoint=None, view_func=Login.as_view('/login')) #本来写的是login,但是经过测试又报了名字重复的错误
if __name__ == '__main__':
app.run('0.0.0.0', 5000, debug=True)
1.3 其他补充
1.3.1 flask的return值有几种?
答:5种.
- Flask中的HTTPResponse ---在Flask 中的HttpResponse就是直接返回字符串
- Flask中的Redirect ---自动重定向
- Flask 中的 render (render_template)---里面涉及MarkupSave函数的使用
注意: 如果要使用 render_template 返回渲染的模板,请在项目的主目录中加入一个目录 templates----否则可能会有一个Jinja2的异常 - 打开并返回文件内容 send_file("文件的路径")---(最新版本也可以直接返回f"字符串"(字符串可以用{写入想写入的变量}))
标准JSON格式的Response jsonify({name:1}) # Content-type:application/json
1.3.2 HTTP的请求方式有8种
http的请求方式至少包括增删改查要会!!!
from flask.views import MethodView
class Login(views.MethodView):
#http请求方式 有8种
def get(self): # 获取
pass
def post(self): # 增
pass
def delete(self): # 删除
pass
def put(self): # 更新
pass
对应的是增删改查.
1.3.3 app.run('0.0.0.0')
0.0.0.0 有几个不同的含义,不过当告诉服务器监听了 0.0.0.0,意味着监听每一个可用的网络接口,从服务器进程的角度来看,IP 地址为 127.0.0.1 的环回适配器看起来就像机器上的任何其他网络适配器一样,因此被告知监听 0.0.0.0 的服务器也将接受该接口上的连接。
因此在实际应用中,一般我们在服务端绑定端口的时候可以选择绑定到 0.0.0.0,这样我的服务访问就可以通过主机的多个 ip 地址访问我的服务。
私有地址与公有地址不同,并不是由Internet分配的,是不允许出现在Internet中的,我们在公网中是看不到私有IP地址的,并且公有地址也不会使用上述的三类地址。所以,私有地址是不能直接与Internet连接的。
而如果想用私有地址与Internet连接来访问公网,那该怎么做?这就需要将私有IP地址转换成公网IP地址,与外部连接。所以,我们平时使用的路由器中会装有一个叫做 NAT(网络地址转换) 的软件,我们的路由器中会至少会有一个有效的公网IP,NAT会将我们的私有地址转成路由器中的公网IP与外部Internet连接。而同样的,因为使用的是路由器中的公共的公网IP来连接Internet,所以这个内网中的PC在Internet中显示的都是路由器的公共IP,这样做不仅提供了一定程度的安全,也可以有效的减缓可用的IP地址空间的枯竭问题。(像我们学校或者公司的内网一般都是这么做的)
另外还有一点,在同一个局域网内,IP地址是唯一的;但是在不同的局域网内,IP地址是可以重复出现的。
几个域名的比较:
localhost:
localhost其实是域名,一般windows系统默认将localhost指向127.0.0.1,但是localhost并不等于127.0.0.1,localhost指向的IP地址是可以配置的
127.0.0.1:
首先我们要先知道一个概念,凡是以127开头的IP地址,都是回环地址(Loop back address),其所在的回环接口一般被理解为虚拟网卡,并不是真正的路由器接口。
所谓的回环地址,通俗的讲,就是我们在主机上发送给127开头的IP地址的数据包会被发送的主机自己接收,根本传不出去,外部设备也无法通过回环地址访问到本机。
小说明:正常的数据包会从IP层进入链路层,然后发送到网络上;而给回环地址发送数据包,数据包会直接被发送主机的IP层获取,后面就没有链路层他们啥事了。
0.0.0.0:(监听所有端口)
首先,0.0.0.0是不能被ping通的。在服务器中,0.0.0.0并不是一个真实的的IP地址,它表示本机中所有的IPV4地址。监听0.0.0.0的端口,就是监听本机中所有IP的端口。
本机IP:
本机IP通常仅指在同一个局域网内,能同时被外部设备访问和本机访问的那些IP地址(可能不止一个)。像127.0.0.1这种一般是不被当作本机IP的。本机IP是与具体的网络接口绑定的,比如以太网卡、无线网卡或者PPP/PPPoE拨号网络的虚拟网卡,想要正常工作都要绑定一个地址,否则其他设备就不知道如何访问它。
二 回顾flask基础
2.1 flask的优势和劣势
flask优势:
轻量级框架,扩展性,三方组件全
flask劣势:
太轻了(框架),只有个session,轻到连内存都能接受;
组件是第三方的,稳定性相对较差.
2.2 依赖包
pip3 install flask
安装完flask的时候就会全部安装.
Flask 源码
Jinja2 模板语言
MarkupSafe 处理标签语言 render_template里面应用了MarkupSafe,否则就是输出txt了
Werkzeug 德语工具的意思,承载flask程序werkzeug约等于UWSGI,几乎一样(本质都是wsgi,前者更轻,但是不如后者稳定,有一个run_simple(),也就是app.run())
2.3 启动Flask
2.3.1 flask的简单启动
from flask import Flask
app = Flask(__name__)
app.run('0.0.0.0',9527) # 监听当前机器的所有ip,只写127.0.0.1只监听本地地址
2.3.2 路由视图
@app.route('/index',methods=['GET','POST''],endpoint='index')
def index():
return "hello"
补充:
- endpoint是做mapping的;
- methods 当前路由允许的请求方式
- endpoint Mapping -> "/index":{"index":index}
2.3.3 FlaskResponse
- render_template() 类似django的render(),帮助打开文件(HTML),认为文件内容是不安全的,显示出txt文件,这个函数里面有MarkupSafe,让浏览器认为标签是安全的.正常显示.
- redirect("/login") 重定向
- "" 直接返回字符串(django里面需要返回HttpResponse)
- jsonify #content-type:application/json 1.1.1 新特性,可直接返回dict类型,本质上就是在jsonify({'a':1}) ,而且只识别ASCII码. 用于API.
- send_file #自动打开并返回文件内容识别文件类型 content-type:文件类型
2.3.4 FlaskRequest
from flask import request #公共变量 LocalProxy对象
request.form.get() #django是这么写的request.POST.get(),而且flask没法拿文件,django的可以拿. -> .to_dit()
request.args.get() #django的是request.GET.get() -> .to_dict()
request.files.get() #获取文件,django获取方法在上文
request.method() #获取method,类似django
request.headers
request.cookie
request.path
request.url
request.host
request.host_url
# 特别狠的角色
request.json #请求头中带content-type:application/json
request.data #content-type无法被识别 或者 没有Form
注意,
类名的话一般是驼峰体,ToDict.
方法的话一般是下划线,to_dict.
2.3.5 Session
from flask import session
app.secret_key = '@#$%^&*HVxghjk'
def vf():
session["name"] = 1
存储在Cookies中
序列化 - {name:1} -> serect_key + 时间 + 签名 ->生成一个字符串->SESSION_COOKIE_NAME:"生成一个字符串"
反序列化 - SESSION_COOKIE_NAME:"生成一个字符串" ->secret_key + 时间 + 前面 >{name:1}
2.3.6 Flask配置
2.3.6.1 初始化 - app = Flask(name)
- template_folder
- static_folder
- static_url_path
2.3.6.2 Config Flask对象配置
Flask.default_config 获取默认配置
DEBUG
TESTING
SESSION_COOKIE_NAME
SECRET_KEY
settings.py
class DebugSetting(obj):
DEBUG = True
SECRET_KEY = 'adsfghjkhl!#$%@^'
SESSION_COOKIE_NAME = 'i am not SESSION'
Flask.config.from_obj()
Flask.config['debug'] = True
2.3.7 蓝图
from flask import Bluepoint
不能被run的flask实例,没有config
蓝图作用 --- app隔离,URL管理
userBP = Blueprint("userBP",__name__,url__prefix="/user")
@userBP.route('/userBP')
def user_bp():
return ""
思考:如何在蓝图中使用CBV结构.
2.3.8 特殊装饰器
- before_request #请求进入视图函数之前
- after_request # 结束视图函数之后,响应客户端之前
be+af实现中间件:
正常周期:be1 - be2 - vf - af2 - af1
异常周期:be1 - af2 - af1
- errorhandler(HTTP_ERROR_CODE 5xx 4xx) #重定义错误信息
- template_global 全局变量(def ab(a,b): return a+b,都可以用到jinja2里面了)
- route.
(template global要记得)
2.3.9 CBV
from flask import views
class Login(views.MethodView):
methods = []
def get(self): #满足HTTP协议的8种请求
pass
def post(self):
pass
Flask.add_url_rule(rule='/login',endpoint=None,view_func=Login.as_view(name="login"))
2.3.10 其他
三 面向对象补充
3.1 __doc__
class Foo:
'我是描述信息'
pass
print(Foo.__doc__)
它类的描述信息
注意,__doc__无法继承给子类.
3.2 __module__与__class__
3.2.1 概念
module 表示当前操作的对象在那个模块
class 表示当前操作的对象的类是什么
module:模块
python的module说白了就是Python文件,而python文件一般后缀为py,就是你的xxx.py而已.
MODULE的功能:
MODULE里面可以声明变量,经常用来声明程序中所需要的常量,或者用来存放全局变量。
MODULE里面可以定义自定义类型,再经过USE命令让程序中每一个函数都能使用这个类型。
MODULE里面可以编写函数,通常会把功能相关的函数放在同一个MODULE中。要是用这些函数,同样用use命令。
MODULE里面的函数,可以直接使用同一个。
补充:
关于module和library,前者一般在python说,后者在C,C#说.
关于module和package,前者是单个模块(一般是单个(偶尔是多个)python文件);后者是多个相关的module的组合,肯定是多个,相关的,Python文件的组合,是把相关的模块组织在一起,成为一个整体的.
3.2.2 实例
a.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class C:
def __init__(self):
self.name = ‘SB'
lib/aa.py
lib/aa.py
from lib.aa import C
obj = C()
print obj.__module__ # 输出 lib.aa,即:输出模块
print obj.__class__ # 输出 lib.aa.C,即:输出类
index.py
3.4 __del__
__del__是析构方法,当对象在内存中被释放的时候,自动触发执行.
注意,若产生的对象仅仅是用户级的(python程序级别的),那么无需定义__del__,若,产生的对象同时像操作系统发起系统调用,也就是一个对象同时有用户级和内核级两种资源,比如(打开一个文件,创建一个数据库链接),则必须在清除对象的同时回收系统资源,这就用上了__del__.
class Foo:
def __del__(self):
print('执行我啦')
f1=Foo()
# del f1
print('------->')
#输出结果
------->
执行我啦
典型应用场景:
创建数据库类,用该类实例化出数据库链接对象,对象本身是存放于用户空间内存中,而链接则是由操作系统管理的,存放在内核空间内存中.
当程序结束后,python自动回收自己的内存空间,也就是用户态内存,而操作系统的资源没有被回收,这就需要我们定制__del__,在对象被删除前项操作系统发起数据库链接的系统调用,回收资源.
3.5 __enter__和__exit__
3.5.1 概念
__exit__()
中的三个参数分别代表异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都无法执行
如果__exit__()
返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行
用途或者说好处:
1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预
2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处
3.5.2 实例1
class Open:
def __init__(self,name):
self.name=name
def __enter__(self):
print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
# return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('with中代码块执行完毕时执行我啊')
with Open('a.txt') as f:
print('=====>执行代码块')
# print(f,f.name)
3.5.3 实例2
class Open:
def __init__(self,name):
self.name=name
def __enter__(self):
print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
def __exit__(self, exc_type, exc_val, exc_tb):
print('with中代码块执行完毕时执行我啊')
print(exc_type)
print(exc_val)
print(exc_tb)
return True
with Open('a.txt') as f:
print('=====>执行代码块')
raise AttributeError('***着火啦,救火啊***')
print('0'*100) #------------------------------->不会执行
3.6 __call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__
方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj() # 执行 __call__
3.7 metaclass
元类是类的类,是类的模板元类是用来控制如何创建类的.
正如类是创建对象的模板一样,而元类的主要目的是为了控制类的创建行为.
元类的实例化的结果为我们用class定义的类,正如类的实例为对象.
(f1对象是Foo类的一个实例,Foo类是 type 类的一个实例)
type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象
四 入门flask第三方包
4.1 Flask-Session
4.1.1 概念与原理重述
-------------------过度过度-------------------
在使用flask写应用程序的时候,我们会使用session来控制用户会话状态,但是我们无法确定session的保存位置,默认的flask保存session是模糊的,那我们可不可以控制session的存储位置呢,这就是flask-session:增加了服务器端支持会话到您的应用程序.
flask中session原理重述:
flask的session是基于cookie的会话保持。简单的原理即:
当客户端进行第一次请求时,客户端的HTTP request(cookie为空)到服务端,服务端创建session,视图函数根据form表单填写session,请求结束时,session内容填写入response的cookie中并返回给客户端,客户端的cookie中便保存了用户的数据。
当同一客户端再次请求时, 客户端的HTTP request中cookie已经携带数据,视图函数根据cookie中值做相应操作(如已经携带用户名和密码就可以直接登陆)。
在 flask 中使用 session 也很简单,只要使用 from flask import session 导入这个变量,在代码中就能直接通过读写它和 session 交互。
关于源码中最核心的三句话:
s = self.get_signing_serializer(app)
val = request.cookies.get(app.session_cookie_name)
data = s.loads(val, max_age=max_age)
return self.session_class(data)
注意,参数如下:
secret_key:密钥。这个是必须的,如果没有配置 secret_key 就直接使用 session 会报错
salt:为了增强安全性而设置一个 salt 字符串(可以自行搜索“安全加盐”了解对应的原理)
serializer:序列算法
signer_kwargs:其他参数,包括摘要/hash算法(默认是 sha1)和 签名算法(默认是 hmac)
flask内置session无法满足生产需求。因为将session数据全部保存在cookie中不安全且cookie存储数据量有限,但flask-session组件帮我们实现了将数据保存在服务器''数据库''中而只将sessionID保存在cookie中.
-------------------过度到Flask-Session咯........-------------------
重点啊鸭:
flask-session是flask框架的session组件,由于原来flask内置session使用签名cookie保存,该组件则将支持session保存到多个地方
例如:
redis:保存数据的一种工具,五大类型。
memcached
filesystem
mongodb
sqlalchmey:那数据存到数据库表里面
应用场景:
如果应用程序比较小,就用原生的加密cookie 保存session(内置);
如果应用程序比较大,就用redis(flask-session)
4.1.2 使用步骤
首先,要注意一件事情,使用了Session的话那就意味着放弃了自定义的secret_key,这个的话必然会报一个错误(未定义秘钥,实际上是没地方存储session),所以需要使用redis(实际上支持session保存到多个地方(以上5种都可以),这里我们选择redis).
4.1.2.1 安装Flask-Session
pip install flask-session
pip install redis
注意,pip要切换到pip所在的那个地方,或者把pip进行path环境变量的匹配.
app.config['SESSION_TYPE'] = 'redis' #设置会话接口
app.config['SESSION_REDIS'] = Redis(host='192.168.16.18', port=6379, db=7) #配置连接redis
上面两条命令非常重要!!!
redis下载完模块之后就可以导入了.
然后去官网下载软件,点击下载
安装完成后,无论是建立path环境变量然后再cmd启动redis-server.exe或者是直接运行redis-cli.exe都行.
redis的操作和Linux的一样.
redis最多可操作15条数据隔离的线路.
命令:
select 0~15: 选择任一数字会切换到该线路,select 0是还原(取消线路),在pycharm中进行构造的数据通过redis可查. (会相互影响)
set a1 b1 :建立a1:b1的键值对,(pycharm也可查)
get a1:查找键为a1的值.
更多redis命令猛击这里
4.1.2.2 使用
from flask import Flask, render_template, redirect, session
from flask_session import Session
from redis import Redis
app = Flask(__name__)
app.secret_key = 'dsaf'
app.config['SESSION_TYPE'] = 'redis' #设置会话接口
app.config['SESSION_REDIS'] = Redis(host='192.168.16.18', port=6379, db=7) #配置连接redis
# 测试pycharm和redis的连通性
a1 = Redis(host='192.168.16.18', port=6379, db=6)
a2 = Redis(host='192.168.16.18', port=6379, db=8)
a1.set('b1','123')
a2.set('b2','323')
print(a1.get('b1'))
# 以上是测试内容
Session(app) # 装载app到Session
@app.route('/index')
def index():
session['k'] = 'v'
return '123'
if __name__ == '__main__':
app.run('0.0.0.0', 5000, debug=True)
注意,Session(app)的位置, 写错就会报错.
会话接口及对应的连接配置
一般情况下我们配置好SESSION_TYPE,然后把连接配置配置一下就可以。
- null:NullSessionInterface(默认)
- redis:RedisSessionInterface
连接配置:SESSION_REDIS:一个redis.Redis例如,默认连接到 127.0.0.1:6379 - memcached:MemcachedSessionInterface
连接配置:SESSION_MEMCACHED:一个memcache.Client实例,默认连接到127.0.0.1:11211 - filesystem:FileSystemSessionInterface
连接配置:SESSION_FILE_DIR:存储会话文件的目录。默认使用当前工作目录下的flask_session目录。
连接配置:SESSION_FILE_THRESHOLD:会话在开始删除之前存储的最大项目数,默认值为500
连接配置:SESSION_FILE_MODE:存会话文件所需的文件模式,默认为0600 - mongodb:MongoDBSessionInterface
连接配置:SESSION_MONGODB:一个pymongo.MongoClient实例,默认连接到127.0.0.1:27017
连接配置:SESSION_MONGODB_COLLECT:您要使用的MongoDB集合,默认为“sessions” - SQLAlchemy:SqlAlchemySessionInterface
连接配置:SESSION_SQLALCHEMY:flask_sqlalchemy.SQLAlchemy实例,其数据库连接URI是使用配置SQLALCHEMY_DATABASE_URI参数
连接配置:SESSION_SQLALCHEMY_TABLE:要使用的SQL表的名称,默认为“sessions”
参考:
4.1.3 错误
RuntimeError: The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret.
出现这种错误说明secret_key没写或者是Session初始化之后才发生的,写上或者调整顺序即可.
错误代码:
from flask import Flask,render_template,redirect,session
from flask_session import Session
from redis import Redis
app = Flask(__name__)
Session(app)
app.secret_key='dsaf'
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = Redis(host='192.168.16.18',port=6379,db=7)
@app.route('/index')
def index():
session['k'] = 'v'
return '123'
if __name__ == '__main__':
app.run('0.0.0.0',5000,debug=True)
正确代码:(应该把Session(app)放下面的,创建app这个flask类对象,配置完秘钥,配置完config,然后启动session就好了,就能把session存到你想存到的数据库了,此时我们也链接这这个数据库):
from flask import Flask,render_template,redirect,session
from flask_session import Session
from redis import Redis
app = Flask(__name__)
app.secret_key='dsaf'
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = Redis(host='192.168.16.18',port=6379,db=7)
Session(app)
@app.route('/index')
def index():
session['k'] = 'v'
return '123'
if __name__ == '__main__':
app.run('0.0.0.0',5000,debug=True)
4.1.5 其他
Flask-Session:session会话
Flask-CORS:跨域
Flask-WTF:相当于django的form表单
Flask-SQLAlchemy ORM:SQL操作
所有的flask第三方组件,都是需要app.config,不但要使用配置项,还可能会更改和添加配置项.
注意:
所有的redis不要和web服务器放在一起,redis的要放在内网服务器.redis有bug,无法修复,所以redis不要暴露在外网.!!!
select最高能到15.(同时隔离出15个数据),select 几就是几.
此外,
open_session 反序列化
save_session 序列化
上述两个操作有时间请练.
关于API的操作更适合使用CBV.
实例如下:(Session的配置项)
4.1.6 最终代码
主程序运行
from flask import Flask, request, render_template, redirect, session
from flask_session import Session
from redis import Redis
# 导入写好的蓝图模块
from blueprint.viewer import login, index1
app = Flask(__name__)
# 进行配置
app.config['DEBUG'] = True
app.secret_key = 'asdfghjkjhrge'
# 设置会话接口
app.config['SESSION_TYPE'] = 'redis'
# 配置连接redis
app.config['SESSION_REDIS'] = Redis(host='192.168.16.18', port=6379, db=8)
# 类导入配置(注意使用app.default_config(如果忘记了的话))
from config_mode.settings import DebugSettings, TestSettings
app.config.from_object(DebugSettings)
# app.config.from_object(TestSettings)
# 装载app到Session
Session(app)
# 特殊装饰器
@app.before_request
def is_login():
if request.path == '/login':
return None
if not session.get('uname'):
return redirect('login')
# 报错信息(404的)
@app.errorhandler(404)
def error404(error_message):
print(error_message)
return redirect(
'https://gitee.com/python_stack_20/teaching_plan/issues/IZ16D%E6%92%92%E6%89%93%E9%A3%9E%E6%9C%BA%E8%80%83%E6%A0%B8%E6%B3%95%E7%AC%AC%E4%B8%89%E6%96%B9%E7%9A%84%E8%90%A8%E5%87%A1%E7%BA%B3%E7%9A%84v')
app.register_blueprint(login)
app.register_blueprint(index1)
if __name__ == '__main__':
app.run('0.0.0.0', 5000)
# 项目问题:暂时不会把404写到蓝图中,只会把蓝图中的化为CBV.
蓝图所在py文件(viewer.py)
from flask import Blueprint, request, redirect, session, render_template
from flask.views import MethodView
login = Blueprint('login1', __name__)
# 登录
class Login(MethodView):
def get(self):
return render_template('login.html')
def post(self):
uname = request.form.get('username')
pwd = request.form['password']
if uname == '123' and pwd == '123':
session['uname'] = uname
return redirect('index')
else:
return redirect('login')
login.add_url_rule('/login', endpoint='login1',view_func=Login.as_view('login'))
index1 = Blueprint('index', __name__)
# 主页
class Index(MethodView):
def get(self):
return render_template('index.html')
index1.add_url_rule('/index',endpoint='index',view_func=Index.as_view('index'))
标签:__,新篇章,flask,0.0,app,Flask,session 来源: https://www.cnblogs.com/smithpath/p/11178581.html