首先明确浏览器的html是无状态的(因为你是用的http协议是无状态的),即当你打开关闭浏览器后你再向服务器发送相同请求的时候,你原本浏览网页上面不会记录你之前的状态信息,及可能当你登录了一次之后刷新一次就需要重新登录,或者在一次编辑为完成之后误关闭在打开也不会有原本的状态信息
cookie就是为了解决用户在服务器请求状态信息的保存而诞生的
2.cookie的工作过程,与工作原理cookie是在服务器端创建的,但随着第一次响应信息在返回给浏览器的客户端,然后保存在浏览器的客服端中,在之后进行访问的时候可以附上此cookie信息
原理:
客户端请求服务器时,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个cookie。而客户端浏览器会把cookie保存起来。当浏览器再请求服务器时,浏览器把请求的网址连同该cookie一同提交给服务器。服务器通过检查该cookie来获取用户状态。
3.cookie的注意问题cookie的容量是很小的,它以键值对的形式存放少量的数据
cookie的保存状态信息是有时间限制的
cookie的状态信息保存映射是与域名相对应的
4.cookie的使用方式创建:
1.cookie 是基于response对象的,所以首先导入response,并在需要使用的方法中创建response对象
2.设置cookie,及通过response对象的set_cookie方法进行设置cookie
cookie设置的各项参数
必须的两个参数key,value
两种设置cookie过期时间max_age,expires //若果没有设置那么就一浏览器的打开与关闭为cookie的过期时间
max_age是过多少秒之后,现在比较常用
expires是基于特定时间(格林啥的时间)
删除
1:使用python代码,使用response对象的delete_cookie方法,需要指定key,value
xxx.delete_cookie(key,value)
2.通过浏览器设置进行删除
5.cookie设置有效域名首先设置有效的子域名得使用蓝图,先用蓝图把子域名配置好
1.首先使用蓝图技术,在创建蓝图对象的时候设置subdomain=‘xxx’
2.在主类注册之后,还需要进行app.config配置的SERVER_NAME
app.config['SERSER_NAME']='xxx.xxx:ddd'
3. 在`C:WindowsSystem32driversetc`下,找到hosts文件,然后添加域名与本机的映射。 域名和子域名都需要做映射。例如:
127.0.0.1 momo.com
127.0.0.1 cms.momo.com
配置好子域名后在response对象.set_cookie中传递domain,domain的配置为完整的域名配置
//在子域名前面还需要加上一个.
二、session1.什么是session?session机制是为了解决什么而诞生的?
session与cookie一样都是为了解决http无状态的缺点而衍生的,
session又名会话技术,它与cookie的一个最大不同在于session是在服务器建立的,而cookie是在客户端建立存储用户信息的
session的出现主要是为了解决cookie机制的安全问题
2.session的工作过程
简单说,客户端发送cookie用户信息给服务器,服务器在第一次接受到cookie之后建立起session(可以看为容器),并将用户信息存放进去,服务器利用盐将数据进行加密之后产生一个用于标识的乱码(session_id),再
作为响应信息的cookie返回到客户端,此时客户端存放的cookie就是服务器加密后的乱码
(session_id)。
总结:
*服务器端功能:
1.把用户的相关信息存储到服务器端的session中
2.通过盐的机制加密随机生成一个唯一的session_id,用来标识用户相关信息并将session_id也存入session中
3.把session作为cookie的key,session_id作为cookie的value创建cookie信息并返回给客户端
4.客户端发送第二次以后的请求时,获取cookie信息,与服务器端session容器中session_id对比,得出指定 用户信息。
* 客户端功能:
1.通过cookie存储session加密后的session_id信息
2.以后浏览器再请求服务器的时候,就会自动的把cookie信息(包含session_id)发送给服务器
session操作
1.设置session(
session的设置类似于字典,导入之后
session【‘’xxx‘’】=aaa
2.获取session
也类似字典
session.get(key)
3.删除session
*session.pop(key)
*session.clear()删除全部
4.设置session有效日期:默认session有效时间关闭浏览器之后
将session.permanent=True
设置后是默认为31天
如果不想设置为31天可以进行修改app设置中的permanent_session_lifetime
app.config['PERMANENT_SESSION_LIFETIME']=timedelta(hour=2)`在两个小时后过期。
三、Local对象隔离线程间的对象_即ThreadLocal变量
1.Local对象:
在Flask中,类似于request对象,其实是绑定到了一个werkzeug.local.Local对象上
from werkzeug.local import Local
当浏览器访问服务器的时候它并不是全部都通过一个80端口然后创建一个request就进行访问了,
而是通过80端口然后创建出不同的线程request再与Flask应用进行交互
2.ThreadLocal变量:
Python提供了ThreadLocal 变量,它本身是一个全局变量,
但是每个线程却可以利用它来保存属于自己的私有数据,
这些私有数据对其他线程也是不可见的。
只要满足绑定到"local"或"Local"对象上的属性,在每个线程中都是隔离的,那么他就叫做`ThreadLocal`对象,也叫'ThreadLocal'变量。
补充:g对象
Flask_线程隔离的g对象使用详解:
保存为全局对象g对象的好处:
- request一样,是线程隔离的。
- Flask程序中都可以使用。
- g上面取就可以了,而不需要通过传参的形式,这样更加方便。
适用场合:当多个业务需要同一形参并且多个用户使用的时候
四:上下文
1.Flask_app上下文
aoo上下文也叫应用上下文,是存放在LocalStack的栈中的,和应用app相关的操作就必须使用上下文
eg:通过current_app可以获取当前用app对象的名字
注意1:玩视图函数不用管,系统自动创建current_app自动推
在视图函数中,不用担心应用上下文的问题。因为视图函数要执行,那么肯定是通过访问url的方式执行的,
那么这种情况下,Flask底层就已经自动的帮我们把应用上下文都推入到了相应的栈中。
如果不是视图函数需要手写
过程:
1.导入 form flask import current_app
2.创建上下文app_context=app,app_context()
3.将创建的app对象推入栈app_context.push
4.然后可以进行上下文操作
还可以使用with函数创建
直接with app.app_context():
使用上下文函数
//视图函数直接就可以使用上下文函数
上下文原理图解:
2.Flash_request上下文
Flash_request请求上下文:请求上下文也是存放到LocalStack的栈中
和请求相关的操作必须使用请求上下文eg:url_for反转视图函数
注意1:任然是视图函数不用管
在视图函数中,不用担心请求上下文的问题。
因为视图函数要执行,那么肯定是通过访问url的方式执行的,
那么这种情况下,Flask底层就已经自动的帮我们把应用上下文和请求上下文都推入到了相应的栈中。
手推上下文过程:
底层代码执行说明:
* 推入请求上下文到栈中,会首先判断有没有应用上下文,
* 如果没有那么就会先推入应用上下文到栈中,
* 然后再推入请求上下文到栈中
使用方法:
with app.test_request_context()
四、钩子函数
钩子函数在Flask中指的是特定装饰器的函数
根据特定的函数装饰器可以让程序在执行下面函数的过程中插入一段自己需要执行的代码
常见的钩子函数
before_frist_request:处理项目的第一次请求之前执行。
before_request:每次请求之前执行,通常可以用这个装饰器来给视图函数增加一些变量。请求已经到达了Flask,但是还没有进入到具体的视图函数之前调用。一般这个就是在视图函数之前,我们可以把一些后面需要用到的数据先处理好,方便视图函数使用。
treadown_appcontext:管是否有异常,注册的函数都会在每次请求之后执行。
template_filter:Jinja2模板的自定义过滤器
context_processor:上下文处理器。使用这个钩子函数,必须返回一个字典。这个字典中的值在所有模版中都可以使用。这个钩子函数的函数是,如果一些在很多模版中都要用到的变量,那么就可以使用这个钩子函数来返回,而不用在每个视图函数中的`render_template`中去写,这样可以让代码更加简洁和好维护。
@app.context_processor def context_processor():
if hasattr(g,'user'):
return {"current_user":g.user}
else:
return {}
errorhandler:errorhandler接收状态码,可以自定义返回这种状态码的响应的处理方法。在发生一些异常的时候,比如404错误,比如500错误,那么如果想要优雅的处理这些错误,就可以使用`errorhandler`来出来
五丶 Flask信号机制flask信号机制使用的是第三方插件blinker
1.自定义信号步骤:
创建信号,使用blinker包中的Namespace类创建一个命名空间
mysigle=Namespace()
signall=mysigle.single(‘信号名’)
.监听信号,使用signall对象的connect方法,这个方法需要传递一个函数及当他触发之后需要调一个函数执行
def func1(sender,uname):
print(sender)
print(uname)
signal1.connect(func1)
发送信号:使用signall对象的send方法,send方法也可以同时进行参数传递
//补充资料Flask中文信号网
信号 — Flask 0.10.1 文档
Flask信号使用场景--存储用户的登录日志
:定义一个登录信号,等用户登录后发送,定义监听事件为登录之后存储这个用户登录信息
from flask import request,g
from datetime import datetime
from blinker import *
mysinge=Namespace()
logsige=mysinge.signal("login")
def cun(sender):
now=datetime.now()
ip=request.remote_addr
log_data="{uname}*{now}*{ip}".format(uname=g.uname,now=now,ip=ip)
with open('login_log.txt','a') as f:
f.write((log_data+"/n"))
f.close()
logsige.connect(cun)
from flask import Flask, request, g
from singels import mysingles
app = Flask(__name__)
@app.route('/login/')
def login():
uname = request.args.get('uname')
if uname:
g.uname = uname
mysingles.logsige.send()
return "登录成功"
else:
return "请输入用户名称"
if __name__ == "__main__":
app.run(debug=True)
2.Flask内置的常用信号
其实主要的就是template_rendered与got_request_exception两个
1. template_rendered:模版渲染完成后的信号。
2. before_render_template:模版渲染之前的信号。
3. request_started:请求开始之前,在到达视图函数之前发送信号。
4. request_finished:请求结束时,在响应发送给客户端之前发送信号。
5. request_tearing_down:请求对象被销毁时发送的信号,即使在请求过程中发生异常也会发送信号。
6. got_request_exception:在请求过程中抛出异常时发送信号,异常本身会通过exception传递到订阅(监听)的函数中。一般可以监听这个信号,来记录网站异常信息。
7. appcontext_tearing_down:应用上下文被销毁时发送的信号。
8. appcontext_pushed:应用上下文被推入到栈上时发送的信号。
9. appcontext_popped:应用上下文被推出栈时发送的信号。
10. message_flashed:调用了Flask的`flash`方法时发送的信号。
代码演示:
template_rendered的使用:
六、验证机制WTforms
1.介绍:
WTform插件主要就是做表单的验证,之前我们做验证都是在网页也可以说是客户端,而WTForm是在服务器端做验证
Flask-WTF是简化了WTForm的一个第三方库
WTForms表单的两个主要功能是验证用户提交数据的合法性以及渲染模板。而Flask-WTF还包括一些其他的功能:CSRF保护,文件上传等。
安装Flask-WTF默认也会安装WTForms,因此使用以下命令来安装Flask-WTF和WTForms:
| pip install flask-wtf |
2.使用步骤:
1.自定义一个表单类继承wtforms.Form类
2.定义需要验证的字段,字段的名字与模板中验证的input标签的name属性一致
3.在需要验证的字段上,指定所属的数据类型,并调用指定的验证其
4.以后在视图函数中,只需要使用这个表单类的对象,把需要验证的数据(request。form)串给这个给表单类,在调用表单类对象的validate方法(返回值为bloon)验证,
可以使用表单类对象的errors属性来获取验证失败的具体错误信息
代码实现:
from flask import Flask,request,render_template
from wtforms import Form,StringField
from wtforms.validators import Length,EqualTo
app=Flask(__name__)
class Registers(Form):
uname=StringField(validators=[Length(min=2,max=12,message="长度为3-12")])
pwd=StringField(validators=[Length(min=6,max=10)])
pwd2=StringField(validators=[Length(min=6,max=10,message="长度为6-10"),EqualTo('pwd')]) //注意EqualTo里面传递的是字符串必须要‘’,“”
@app.route('/')
def index():
return render_template("Registers.html")
@app.route('/register/',methods=['GET','POST'])
def registers():
if request.method == 'GET':
return render_template('Registers.html')
else:
form = Registers(request.form)
if form.validate():
return "验证通过"
else:
print(form.errors) //注意此时调用的是errors属性
return "验证失败"
if __name__ == "__main__":
app.run()
3.WTForms常用验证器:
页面把数据提交上来,需要经过表单验证,进而需要借助验证器来进行验证,以下是常用的内置验证器:
1. Length:字符串长度限制,有min和max两个值进行限制。
2. EqualTo:验证数据是否和另外一个字段相等,常用的就是密码和确认密码两个字段是否相等。
3. Email:验证上传的数据是否为邮箱数据格式 如:223333@qq.com。
4. InputRequired:验证该项数据为必填项,即要求该项非空。
5. NumberRange:数值的区间,有min和max两个值限制,如果处在这两个数字之间则满足。
6. Regexp:定义正则表达式进行验证,如验证手机号码。
7. URL:必须是URL的形式 如http://www.bjsxt.com。
8. UUID:验证数据是UUID类型。
4.自定义验证器:
在后期当我需要很多验证器的的时候为了保证代码的质量,直接创建以一个验证.py专门存放囊验证类,
而为了应对多种不同需求,当WTFroms内置验证器不满足我们的使用需求的时候可以进行自定义验证器:
自定义验证类的创建步骤:
1.创建一个验证类:定义方法,方法命名规则为:validate_字段名(selg,field)
2.在方法使用中可以使用field.data获取这个字段的具体值
3.验证的时候,如果数据满足条件,那么可以什么都不做,如果验证失败则应该抛出一个异常
wtfroms.balidators.ValidationError并键这个歌失败验证的的信息传入这个异常类中
代码实现:验证码验证
from wtforms import *
from flask import session
from wtforms.validators import *
class RegisterForm2(Form):
def validate_code(self, filed):
print(filed.data,session.get('code'))
scode=session.get('code')
if filed.data != scode:
raise ValidationError(message="验证码输入错误")
import random
@app.route('/register2',methods=['GET','POST'])
def login():
if request.method== 'GET':
code =random.randint(1000,9999)
session['code']=str(code)
return render_template('register2.html')
else:
form = RegisterForm2(request.form)
if form.validate():
return "ok"
else:
return "NO"
六丶Flask上传文件:
1.上传文件的步骤:
在html中需要为表单添加 encotype='multipart/form-data'才能进行上传文件
在后台需要获取上传的文件,那么应该使用request.files.get('文件名')
保存文件之前,可以使用werkzeug.utils.secure_filename来对上传文件的文件名进行过滤,保证不会存在安全问题
获取上传上来的文件后,使用文件对象.save(路径)方法来保存文件,路径为=路径名+文件名



