5.flask知识点补充
1.WTForms表单验证基本使用
flask-wtf是一个简化了WTForms操作的一个第三方库,WTForms表单的两个主要的功能jiushi就是验证用户提交数据的合法性以及渲染模板。当然还包括其他的功能:CSRF保护,文件上传等等。安装flask-wtf也会默认安装wtforms。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/register" method="post">
<table>
<tbody>
<tr>
<td>姓名:</td>
<td><input name="username" type="text"></td>
</tr>
<tr>
<td>密码:</td>
<td><input name="password" type="password"></td>
</tr>
<tr>
<td>重复密码:</td>
<td><input name="repeat_passwd" type="password"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="立即注册"></td>
</tr>
</tbody>
</table>
</form>
</body>
</html>
from flask import Flask, request, render_template
from wtforms import Form, StringField
from wtforms.validators import Length, EqualTo
app = Flask(__name__)
class RegisterForm(Form):
# 我们这里的左值,就是html里面的name="username",这里一定要保持一直,否则不会验证
# 这里传入一个列表,因为验证条件会有多个,所以以列表形式传值,这里表示长度为6到10位
username = StringField(validators=[Length(min=6, max=10)])
password = StringField(validators=[Length(min=6, max=10)])
# 这里的repeat_passwd必须要和password保持一致,所以这里的Length也可以不要,まぁいいや
repeat_passwd = StringField(validators=[Length(min=6, max=10), EqualTo("password")])
@app.route("/register", methods=["GET", "POST"])
def register():
if request.method == 'GET':
return render_template("register.html")
else:
# 直接将request.form丢进去就可以了
form = RegisterForm(request.form)
if form.validate():
return "登陆成功"
else:
# 没通过的话,那么错误信息会存储在form.errors里面
return f"登录失败:{form.errors}"
if __name__ == '__main__':
app.run(host="localhost", port=8888)






但是这种报错信息似乎显得不友好,因此我们也可以自己指定
class RegisterForm(Form):
# 我们这里的左值,就是html里面的name="username",这里一定要保持一直,否则不会验证
# 这里传入一个列表,因为验证条件会有多个,所以以列表形式传值,这里表示长度为6到10位
username = StringField(validators=[Length(min=6, max=10, message="用户名必须在6到10位")])
password = StringField(validators=[Length(min=6, max=10, message="密码必须在6到10位")])
# 这里的repeat_passwd必须要和password保持一致,所以这里的Length也可以不要,まぁいいや
repeat_passwd = StringField(validators=[Length(min=6, max=10, message="密码必须在6到10位"),
EqualTo("password", message="两次输入的密码不一致")])

2.WTForms常用验证器
常用的验证器:
数据发送过来,经过表单验证,因此需要验证器来进行验证,以下是一些常用的验证器
·Email:验证上传的数据是否为邮箱
·EqualTo:验证上传的数据是否和另外一个字段相等,常用的就是密码和确认密码两个字段是否相等
·LnputRequired:表示该字段为必填项,只要填了就通过,不填就是失败
·Length:长度限制,有min和max两个值进行限制
·NumberRange:数字的区间,有mix和max两个值进行限制,而且必须是数字,如果处在这两个数字之间则满足
·Regexp:自定义正则表达式
·URL:必须要是url的形式
·UUID:必须是UUID的形式
from flask import Flask, request, render_template
from wtforms import Form, StringField
from wtforms.validators import Length, EqualTo, Email, InputRequired, NumberRange, Regexp, URL, UUID
app = Flask(__name__)
class RegisterForm(Form):
email = StringField(validators=[Email()])
username = StringField(validators=[InputRequired()])
age = StringField(validators=[NumberRange(min=18, max=60)])
phone = StringField(validators=[Regexp(r"1\d{10}")])
url = StringField(validators=[URL()])
uuid = StringField(validators=[UUID()])
没有什么技术难度,具体不再演示了
3.自定义表单验证器
from flask import Flask, request, render_template
from wtforms import Form, StringField
from wtforms.validators import Length, EqualTo, Email, InputRequired, NumberRange, Regexp, URL, UUID, ValidationError
app = Flask(__name__)
class RegisterForm(Form):
# 如何自定义表单,比如我们在html里面有一个name="username"
# 那么就需要定义一个函数叫做,validate_username,当验证username的时候,会自动执行相应的函数
username = StringField(validators=[InputRequired()])
def validate_username(self, field):
# field.data,就是我们在html中获取的值
print(type(field)) # <class 'wtforms.fields.core.StringField'>
# 如果全部username全部是数字,那么不允许
if set(field.data) < set("123456789"):
raise ValidationError("用户名不能全为数字")
@app.route("/register", methods=["GET", "POST"])
def register():
if request.method == 'GET':
return render_template("register.html")
else:
# 直接将request.form丢进去就可以了
form = RegisterForm(request.form)
if form.validate():
return "登陆成功"
else:
# 没通过的话,那么错误信息会存储在form.errors里面
return f"登录失败:{form.errors}"
if __name__ == '__main__':
app.run(host="localhost", port=8888)




4.使用wtforms渲染模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.text_color{
color: darkseagreen;
}
</style>
</head>
<body>
<table>
<tbody>
<tr>
<td>{{form.username.label}}</td>
<td>{{form.username(class='text_color')}}</td>
</tr>
<tr>
<td>{{form.age.label}}</td>
<td>{{form.age()}}</td>
</tr>
<tr>
<td>{{form.remember.label}}</td>
<td>{{form.remember()}}</td>
</tr>
<tr>
<td>{{form.tags.label}}</td>
<td>{{form.tags()}}</td>
</tr>
<tr>
<td></td>
<td>
<input type="submit" value="提交">
</td>
</tr>
</tbody>
</table>
</body>
</html>
from flask import Flask, request, render_template
from wtforms import Form, StringField, BooleanField, SelectField
from wtforms.validators import Length, EqualTo, Email, InputRequired, NumberRange, Regexp, URL, UUID, ValidationError
app = Flask(__name__)
class IndexForm(Form):
# 第一个参数指定之后,会自动传到html中的form.username.label,如果不指定,那么自动为左值并且首字母大写
# 而form.username则是一个input标签,这里的左值username到html中就会变成,name="username"
username = StringField("用户名:", validators=[InputRequired()])
age = StringField("年龄:", validators=[InputRequired()])
remember = BooleanField("记住我:")
tags = SelectField("选项:", choices=[("1", "古明地觉"), ("2", "椎名真白"), ("3", "四方茉莉")])
@app.route("/index", methods=["GET", "POST"])
def index():
if request.method == "GET":
form = IndexForm()
return render_template("index.html", form=form)
else:
form = IndexForm()
form = IndexForm(request.form)
if __name__ == '__main__':
app.run(host="localhost", port=8888)

5.上传文件以及访问上传的文件

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<table>
<tr>
<td>头像:</td>
<td><input type="file" name="avatar"></td>
</tr>
<tr>
<td>描述:</td>
<td><input type="text" name="describe"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="提交"></td>
</tr>
</table>
</form>
</body>
</html>
from flask import Flask, request, render_template
import os
app = Flask(__name__)
@app.route("/upload", methods=["GET", "POST"])
def upload():
if request.method == 'GET':
return render_template("upload.html")
else:
describe = request.form.get("describe")
avatar = request.files.get("avatar")
# avatar就是我们所获取的文件
# avatar.filename则是文件名,那么如何将文件保存起来呢?可以直接使用save
# 由于直接使用用户获取的文件名比较危险,那么可以from werkzeug.utils import secure_filename,然后进行转化
avatar.save(os.path.join(os.path.dirname(__file__), "images", avatar.filename))
return f"{avatar.filename}上传成功, 描述信息为{describe}"
app.run(host="localhost", port=8888)



而且我们获取了图片如何让用户访问呢?
@app.route("/images/<filename>")
def get_image(filename):
if os.path.exists(os.path.join(os.path.dirname(__file__), "images", filename)):
# send_from_directory表示将图片直接返回
# 接收两个参数,一个是图片的目录,一个是图片的名字
return send_from_directory(os.path.join(os.path.dirname(__file__), "images"), filename)
else:
return "没有这个玩意儿······"


6.使用flask-wtf验证上传的文件
之前我们接收用户上传的文件,也没有进行判断,比如说用户上传头像,应该是一张图片,可如果用户上传的是txt,或者py文件怎么办呢?这时候我们应该对用户上传的文件进行一个判断.
我们这里新建一个forms.py文件,用于存放form表单。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<table>
<tr>
<td>头像:</td>
<td><input type="file" name="avatar"></td>
</tr>
<tr>
<td>描述:</td>
<td><input type="text" name="describe"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="提交"></td>
</tr>
</table>
</form>
</body>
</html>
from wtforms import Form, FileField, StringField
# FileRequired表示这个文件必须上传,FileAllowed表示允许的文件格式
from flask_wtf.file import FileRequired, FileAllowed
from wtforms.validators import InputRequired
class UploadForm(Form):
avatar = FileField(validators=[FileRequired(), FileAllowed(["jpg", "png", "gif"])])
describe = StringField(validators=[InputRequired()])
from flask import Flask, request, render_template
from forms import UploadForm
from werkzeug.datastructures import CombinedMultiDict
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
@app.route('/upload', methods=["GET", "POST"])
def get_img():
if request.method == 'GET':
return render_template("upload.html")
else:
# 我们既有文件类型,还有一般的表单类型。因此需要把两者组合在一块
form = UploadForm(CombinedMultiDict([request.form, request.files]))
if form.validate():
avatar = request.files.get("avatar")
describe = request.form.get("describe")
'''
此外还可以通过另一种方式获取
<input type="file" name="avatar">
<input type="text" name="describe">
avatar = form.avatar.data
describe = form.describe.data
效果是一样的
'''
return f"上传成功,上传的文件为:{avatar.filename}, 描述信息为:{describe}"
else:
return f"上传失败:{form.errors}"
if __name__ == '__main__':
app.run()





7.cookie的基本概念
pass
8.flask设置和删除cookie
from flask import Flask, Response
app = Flask(__name__)
@app.route('/')
def hello_world():
# 之前说过返回的其实一个Response对象,而我们之所以能直接返回字符串,是因为flask会自动帮我们转化成Response对象
# 但是如果我们想设置cookie必须手动创建Response对象
res = Response("hello world!")
res.set_cookie(key="satori", value="elegant")
return res
if __name__ == '__main__':
app.run()


那么如何删除cookie呢?
@app.route("/del")
def delete():
# 还可以删除cookie,注意删除cookie并不会真正意义上将cookie上删除。而是将cookie的值设为空,有效期改成失效。
# 真正清楚cookie是由浏览器来做的
res = Response("delete cookie")
res.delete_cookie("satori")
return res
9.flask设置cookie的有效时间
@app.route('/')
def hello_world():
# 如何设置cookie的有效时间呢?有两个参数可以设置
# 一个参数是max_age,表示距离现在多少秒之后过期,比方说max_age=60,则60秒之后过期
# 还有一个是expires,需要传入一个datetime类型,我们python自带的就可以,表示过期时间。并且必须传入格林尼治时间,浏览器会自动加八个小时
# expires = datetime.datetime(year=2018, month=11, day=20, hour=0, minute=0, second=0),那么会在2018-11-20 08:00过期
# 所以我们需要在设置的时候,要比期望的时间少8个小时
# 此外expires也可以使用相对时间,expires=datetime.now() + datetime.timedelta(days=30, hour=16),表示31天之后过期
# 如果两者都设置了,那么以max_age为标准,如果都没设置,那么当关闭浏览器时(是关闭浏览器),cookie失效
res = Response("hello world!")
res.set_cookie(key="satori", value="elegant", max_age=None, expires=None)
return res
10.flask设置cookie的有效域名
from flask import Blueprint
bp = Blueprint("cms", __name__, subdomain="cms")
@bp.route('/')
def index():
return "cms page"
from flask import Flask, Response
from book import bp
app = Flask(__name__)
app.register_blueprint(bp)
app.config["SERVER_NAME"] = "satori.com:5000"
@app.route('/')
def hello_world():
return "hello world"
if __name__ == '__main__':
app.run()



from flask import Flask, Response
from book import bp
app = Flask(__name__)
app.register_blueprint(bp)
app.config["SERVER_NAME"] = "satori.com:5000"
@app.route('/')
def hello_world():
res = Response("hello world")
res.set_cookie("satori", "elegant", max_age=1000, domain=".satori.com")
return res
if __name__ == '__main__':
app.run()
from flask import Blueprint, request
bp = Blueprint("cms", __name__, subdomain="cms")
@bp.route('/')
def index():
# 那么如何获取cookie呢?
satori = request.cookies.get("satori")
print(satori)
return "cms page"



11.session的基本概念
pass
12.flask设置session
from flask import Flask, session
import secrets
app = Flask(__name__)
# 设置session,则必须要有一个SECRET_KEY
app.config["SECRET_KEY"] = secrets.token_bytes(20)
@app.route('/')
def hello_world():
# 导入session,会自动交给浏览器
session["name"] = "satori"
return 'Hello World!'
if __name__ == '__main__':
app.run()


@app.route("/get_session")
def get_session():
session_value = session.get("name")
return session_value or "没有获取到session"

@app.route("/delete_session")
def delete_session():
return f'已删除session:{session.pop("name")}' or "没有这个session"

成功删除session:satori,记住一定要先访问,localhost:5000获取session,然后访问delete_session才能删除
from flask import Flask, session
import secrets
app = Flask(__name__)
# 设置session,则必须要有一个SECRET_KEY
app.config["SECRET_KEY"] = secrets.token_bytes(20)
@app.route('/')
def hello_world():
# 我们也可以设置多个session
session["name"] = "satori"
session["age"] = 18
session["anime"] = "东方地灵殿"
return 'Hello World!'
@app.route("/get_session")
def get_session():
session_name = session.get("name")
session_age = session.get("age")
session_anime = session.get("anime")
if session_name and session_age and session_anime:
return f"session:{session_name}--{session_age}--{session_anime}"
else:
return "没有获取到session"
@app.route("/delete_session")
def delete_session():
# 也可以一次行删除所有session,因为导入的session继承自dict
sess = dict(session)
session.clear()
return f"删除session之前:{sess}, 删除之后:{dict(session)}"
if __name__ == '__main__':
app.run()



设置cookie的过期时间
from flask import Flask, session
import secrets
import datetime
app = Flask(__name__)
app.config["SECRET_KEY"] = secrets.token_bytes(20)
# 设置cookie有两种
# 1. app.config["PERMANENT_SESSION_LIFETIME"] = datetime.timedelta(hours=2),两小时后过期
@app.route('/')
def hello_world():
session["name"] = "satori"
session["age"] = 18
session["anime"] = "东方地灵殿"
# 2. session.permanent = True, 表示session默认为31天之后过期
return 'Hello World!'
if __name__ == '__main__':
app.run()
13.csrf攻击原理

14.实战项目-中国工商银行注册功能
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>中国工商银行首页</title>
</head>
<body>
<h1>欢迎来到中国工商银行</h1>
<ul>
<li><a href="{{ url_for('register') }}">立即注册</a></li>
</ul>
</body>
</html>
register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>中国银行注册页面</title>
</head>
<body>
<form action="/register" method="post">
<table>
<tbody>
<tr>
<td>邮箱:</td>
<td><input type="email" name="email"></td>
</tr>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td>重复密码:</td>
<td><input type="password" name="repeat_password"></td>
</tr>
<tr>
<td>余额:</td>
<td><input type="text", name="deposit"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="立即注册"></td>
</tr>
</tbody>
</table>
</form>
</body>
</html>
exts.py
from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy()
models.py
from exts import db
class User(db.Model):
__tablename__ = "user"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
email = db.Column(db.String(50), nullable=False)
username = db.Column(db.String(50), nullable=False)
password = db.Column(db.String(50), nullable=False)
deposit = db.Column(db.Float(50), default=10)
manage.py
from flask_script import Manager
from icbc import app
from flask_migrate import Migrate, MigrateCommand
from exts import db
from models import User
manager = Manager(app)
Migrate(app, db)
manager.add_command("db", MigrateCommand)
if __name__ == '__main__':
manager.run()
forms.py
from wtforms import Form, StringField, FloatField
from wtforms.validators import Length, EqualTo, Email, InputRequired
class RegisterForm(Form):
email = StringField(validators=[Email()])
username = StringField(validators=[Length(6, 20)])
password = StringField(validators=[Length(6, 20)])
repeat_password = StringField(validators=[EqualTo("password")])
deposit = FloatField(validators=[InputRequired()])
icbc.py主程序
from flask import Flask, render_template, request, views
from forms import RegisterForm
from exts import db
from models import User
import config
app = Flask(__name__)
app.config.from_object(config)
db.init_app(app) # 这个和db = SQLAlchemy(app)效果是一样的
@app.route('/')
def index():
return render_template("index.html")
class RegisterView(views.MethodView):
def get(self):
return render_template("register.html")
def post(self):
form = RegisterForm(request.form)
if form.validate():
email = form.email.data
username = form.username.data
password = form.password.data
deposit = form.deposit.data
user = User(email=email, username=username, password=password, deposit=deposit)
db.session.add(user)
db.session.commit()
return "注册成功"
else:
return f"注册失败,{form.errors}"
app.add_url_rule("/register", view_func=RegisterView.as_view("register"))
if __name__ == '__main__':
app.run()
执行python manage.py db migrate 然后执行python manage.py db upgrade,然后会发现数据库多了一张user表

访问localhost:5000



点击立即注册之后,显示注册成功,我们查看一下数据库

发现数据已经被添加到数据库里面了
15.实战项目-中国工商银行登录和转账实现
首页,index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>中国工商银行首页</title>
</head>
<body>
<h1>欢迎来到中国工商银行</h1>
<ul>
<li><a href="{{ url_for('register') }}">立即注册</a></li>
<li><a href="{{ url_for('login') }}">立即登录</a></li>
<li><a href="{{ url_for('transfer') }}">立即转账</a></li>
</ul>
</body>
</html>
注册页面,register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>中国银行注册页面</title>
</head>
<body>
<form action="/register" method="post">
<table>
<tbody>
<tr>
<td>邮箱:</td>
<td><input type="email" name="email"></td>
</tr>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td>重复密码:</td>
<td><input type="password" name="repeat_password"></td>
</tr>
<tr>
<td>余额:</td>
<td><input type="text", name="deposit"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="立即注册"></td>
</tr>
</tbody>
</table>
</form>
</body>
</html>
登录页面,login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>中国工商银行登录页面</title>
</head>
<body>
<form action="/login" method="post">
<table>
<tbody>
<tr>
<td>邮箱:</td>
<td><input name="email" type="email"></td>
</tr>
<tr>
<td>密码:</td>
<td><input name="password" type="password"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="立即登录"></td>
</tr>
</tbody>
</table>
</form>
</body>
</html>
转账页面,transfer.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/transfer" method="post">
<table>
<tbody>
<tr>
<td>转到邮箱:</td>
<td><input type="email" name="email"></td>
</tr>
<tr>
<td>转账金额:</td>
<td><input type="text" name="money"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="立即转账"></td>
</tr>
</tbody>
</table>
</form>
</body>
</html>
py文件只有forms.py和icbc.py发生了变化,其他的没变
form.py
from wtforms import Form, StringField, FloatField
from wtforms.validators import Length, EqualTo, Email, InputRequired, NumberRange
from models import User
class RegisterForm(Form):
email = StringField(validators=[Email()])
username = StringField(validators=[Length(6, 20)])
password = StringField(validators=[Length(6, 20)])
repeat_password = StringField(validators=[EqualTo("password")])
deposit = FloatField(validators=[InputRequired()])
class LoginForm(Form):
email = StringField(validators=[Email()])
password = StringField(validators=[Length(6, 20)])
def validate(self):
result = super(LoginForm, self).validate()
if not result:
return False
email = self.email.data
password = self.password.data
user = User.query.filter(User.email == email, User.password == password).first()
if not user:
self.email.errors.append("邮箱或密码错误")
return True
class TransferForm(Form):
email = StringField(validators=[Email()])
money = FloatField(validators=[NumberRange(min=1, max=1000)])
icbc.py
from flask import Flask, render_template, request, views, session, redirect, url_for
from forms import RegisterForm, LoginForm, TransferForm
from exts import db
from models import User
import config
app = Flask(__name__)
app.config.from_object(config)
db.init_app(app) # 这个和db = SQLAlchemy(app)效果是一样的
@app.route('/')
def index():
return render_template("index.html")
# 注册
class RegisterView(views.MethodView):
def get(self):
return render_template("register.html")
def post(self):
form = RegisterForm(request.form)
if form.validate():
email = form.email.data
username = form.username.data
password = form.password.data
deposit = form.deposit.data
user = User(email=email, username=username, password=password, deposit=deposit)
db.session.add(user)
db.session.commit()
return "注册成功"
else:
return f"注册失败,{form.errors}"
app.add_url_rule("/register", view_func=RegisterView.as_view("register"))
# 登录
class LoginView(views.MethodView):
def get(self):
return render_template("login.html")
def post(self):
form = LoginForm(request.form)
if form.validate():
email = form.email.data
password = form.password.data
user = User.query.filter(User.email == email, User.password == password).first()
if user:
session["session_id"] = user.id
return "登录成功"
else:
return "邮箱或密码错误"
else:
return f"{form.errors}"
app.add_url_rule("/login", view_func=LoginView.as_view("login"))
# 转账
class TransferView(views.MethodView):
def get(self):
# 只有登录了才能转账,否则让其滚回登录页面
if session.get("session_id"):
return render_template("transfer.html")
else:
return redirect(url_for("login"))
def post(self):
form = TransferForm(request.form)
if form.validate():
email = form.email.data
money = form.money.data
user = User.query.filter_by(email=email).first()
if user:
session_id = session.get("session_id")
myself = User.query.get(session_id)
if myself.deposit >= money:
user.deposit += money
myself.deposit -= money
db.session.commit()
return f"转账成功,您向{user.email}转了{money}"
else:
return "您的资金不足,无法完成当前转账"
else:
return "该用户不存在"
else:
return "数据填写不正确"
app.add_url_rule("/transfer", view_func=TransferView.as_view("transfer"))
if __name__ == '__main__':
app.run()












16.实战项目-病毒网站使用CSRF漏洞转账
pass
17.CSRF防御原理
pass
18.flask中CSRF的防御方法与原理
pass
19.Local线程隔离对象
import threading
name = "satori"
class MyThread(threading.Thread):
def run(self):
global name
name = "koishi"
print("子线程:", name) # 子线程: koishi
mt = MyThread()
mt.start()
mt.join()
print("主线程:", name) # 主线程: koishi
'''
可以看到打印的name都是koishi,因为子线程和主线程共享同一份数据
'''
import threading
from werkzeug.local import Local
local = Local()
local.name = "satori"
class MyThread(threading.Thread):
def run(self):
local.name = "koishi"
print("子线程:", local.name) # 子线程: koishi
mt = MyThread()
mt.start()
mt.join()
print("主线程:", local.name) # 主线程: satori
'''
local可以自动隔离,打印的是不同的数据。绑定在local上的数据,线程之间都是隔离的。python的threading也有local,功能类似,但是没有werkzeug里的强大
'''
20.app上下文和request上下文
pass
21.线程隔离的g对象
b.py
from flask import g print(g.name)
from flask import Flask, g
app = Flask(__name__)
@app.route('/')
def hello_world():
g.name = "satori"
import b
return 'Hello World!'
if __name__ == '__main__':
app.run()

22.before_request钩子函数
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
# 加上这个装饰器之后,当flask项目上线之后,第一次请求的时候会执行这个函数
@app.before_first_request
def first_request():
print("第一次请求的时候执行")
# 加上这个装饰器之后,当flask项目上线之后,每一次请求的时候都会执行这个函数
@app.before_request
def request():
print("每一次请求都会执行")
if __name__ == '__main__':
app.run()
23.context_processor钩子函数
from flask import Flask, render_template
app = Flask(__name__)
'''
比方说,我登陆一个页面,只要我登陆了就应该显示我的信息,不管我在那个页面
但是这样,每一个视图都要像这样
'''
@app.route("/index")
def index():
return render_template("index.html", user="satori")
@app.route("/blog")
def blog():
return render_template("blog.html", user="satori")
if __name__ == '__main__':
app.run()
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/index")
def index():
return render_template("index.html")
@app.route("/blog")
def blog():
return render_template("blog.html")
# 这个装饰器就保证了我们在渲染模板的时候不用再传入user="satori"了
@app.context_processor
def context_processor():
return {"user": "satori"}
if __name__ == '__main__':
app.run()
24.errorhandler钩子函数
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/index")
def index():
return "hello world"
# 在出错的时候,不会出现那种英文提示。而是我们自定制的错误提示,当然也可以渲染一个木板,或者重定向到其他页面
@app.errorhandler(404)
def errorhandler():
return "页面找不到啦"
if __name__ == '__main__':
app.run()

from flask import Flask, render_template, redirect, abort
app = Flask(__name__)
@app.route("/index")
def index():
return "hello world"
@app.route("/koishi")
def koishi():
# 比方说这个连接已经不存在了,那么我们可以手动抛出一个错误
# 然后会自动被捕获到
abort(500)
@app.errorhandler(500)
def server_error(error):
return "服务器内部错误,koishi路由被移除了"
if __name__ == '__main__':
app.run()

25.信号机制以及使用场景
from blinker import Namespace
# 1.定义信号
namespace = Namespace()
fire_signal = namespace.signal("fire")
# 2.监听信号
# 首先定义一个回调函数
def open_fire(sender):
print("open fire·····")
# 监听信号,发生则调用回调函数
fire_signal.connect(open_fire)
# 3.发送一个信号
fire_signal.send()
'''
步骤就三步:定义信号,监听信号,发送信号
'''

from flask import Flask, request
from blinker import Namespace
app = Flask(__name__)
# 定义一个登录的信号,以后用户登录进来以后,就发送一个登录信号,然后能够监听这个这个信号
# 在监听到这个信号以后,就记录当前这个用户登录的信息
# 用信号的方式,记录用户的登录信息
# 1.定义信号
namespace = Namespace()
login_signal = namespace.signal("login")
# 2.监听信号
def login_log(sender, user_name):
print(f"用户{user_name},ip:{request.remote_addr}登录了")
login_signal.connect(login_log)
@app.route("/login")
def login():
username = request.args.get("username")
if username:
# 3.发送信号
# 这里面也是可以有参数的,user_name会自动传到login_log里的user_name里
login_signal.send(user_name=username)
return "登陆成功"
else:
return "请输入用户名"
if __name__ == '__main__':
app.run()


26.信号机制以及使用场景

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>欢迎来到避难小屋</h1>
</body>
</html>
from flask import Flask, request, render_template, template_rendered
app = Flask(__name__)
def template_render_func(sender, template, context):
print(template) # <Template '1.html'>
print(context) # {'g': <flask.g of 'app'>, 'request': <Request 'http://localhost:5000/' [GET]>, 'session': <NullSession {}>}
template_rendered.connect(template_render_func)
'''
当我们渲染模板的时候,会自动传过来template和context
'''
@app.route("/")
def index():
return render_template("1.html")
if __name__ == '__main__':
app.run()


template_rendered = _signals.signal('template-rendered') 模板渲染完成后的信号
before_render_template = _signals.signal('before-render-template') 模板渲染前的信号
request_started = _signals.signal('request-started') 模板开始渲染
request_finished = _signals.signal('request-finished') 模板渲染完成
request_tearing_down = _signals.signal('request-tearing-down') request对象被销毁
got_request_exception = _signals.signal('got-request-exception') 视图函数发生异常。一般可以监听这个信号,来记录网站异常信息
appcontext_tearing_down = _signals.signal('appcontext-tearing-down') app上下文被销毁的信号
appcontext_pushed = _signals.signal('appcontext-pushed') app上下文被推入到栈上的信号
appcontext_popped = _signals.signal('appcontext-popped') app上下文被推出到栈上的信号
message_flashed = _signals.signal('message-flashed') 调用了flask的finished方法的信号
5.flask知识点补充的更多相关文章
- swagger知识点补充
1. swagger知识点补充 1.1. 概述 在swagger的使用过程中,除了网上常见的例子,还会有很多细节上的东西需要注意和改写,这里我列几点我使用过程中遇到的问题和改进方式 1.2. 知识点 ...
- set集合,深浅拷⻉以及部分知识点补充
set集合,深浅拷⻉以及部分知识点补充内容:1. 基础数据类型补充2. set集合3. 深浅拷⻉主要内容: ⼀. 基础数据类型补充⾸先关于int和str在之前的学习中已经讲了80%以上了. 所以剩下的 ...
- Django 知识点补充
Django 知识点补充 1 Django如何在Model保存前做一定的固定操作,比如写一条日志 (1)利用Django的Model的Signal Dispatcher, 通过django.db.mo ...
- 从零开始的全栈工程师——html篇1.8(知识点补充与浏览器兼容性)
知识点补充 一.浏览器的兼容问题(关于浏览器的兼容问题 有很多大佬已经解释的很清楚了 这个得自己百度去多花点时间去了解 这里咱们只说一下前面的漏点) 浏览器兼容性问题又被称为网页兼容性或网站兼容性问题 ...
- python day4 元组/字典/集合类知识点补充
目录 python day4 元组/字典/集合类知识点补充 1. 元组tuple知识点补充 2. 字典dict的知识点补充 3. 基本数据类型set 4. 三元运算,又叫三目运算 5. 深复制浅复制 ...
- python 知识点补充
python 知识点补充 简明 python 教程 r 或 R 来指定一个 原始(Raw) 字符串 Python 是强(Strongly)面向对象的,因为所有的一切都是对象, 包括数字.字符串与 函数 ...
- java基础知识点补充---二维数组
#java基础知识点补充---二维数组 首先定义一个二维数组 int[][] ns={ {1,2,3,4}, {5,6,7,8}, {9,10,11,12}, {13,14,15,16} }; 实现遍 ...
- disruptor笔记之八:知识点补充(终篇)
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- Jaeger知识点补充
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
随机推荐
- Gated Recurrent Unit (GRU)
Gated Recurrent Unit (GRU) Outline Backgr ...
- lintcode-52-下一个排列
52-下一个排列 给定一个整数数组来表示排列,找出其之后的一个排列. 注意事项 排列中可能包含重复的整数 样例 给出排列[1,3,2,3],其下一个排列是[1,3,3,2] 给出排列[4,3,2,1] ...
- HDU G-免费馅饼
http://acm.hdu.edu.cn/showproblem.php?pid=1176 Problem Description 都说天上不会掉馅饼,但有一天gameboy正走在回家的小径上,忽然 ...
- python3 urllib和requests模块
urllib模块是python自带的,直接调用就好,用法如下: 1 #处理get请求,不传data,则为get请求 2 import urllib 3 from urllib.request impo ...
- linux mysql 链接数太小
Data source rejected establishment of connection, message from server: "Too many connections&q ...
- Java集合整体框架
Java中的集合类有List.Set.Map Collection的实现类:List.Set List的实现类:ArrayList.LinkedList.Vector Set的实现类:HashSet. ...
- redis集群如何清理前缀相同的key
最近经常收到redis集群告警,每天收到50多封邮件,实在不胜其烦,内存不够用,原因是有一些无用的key(约3000万)占用内存(具体不说了).这部分内存不能被释放. 原来的定期清理脚本的逻辑: 打开 ...
- maven打包遇到的问题
1.javax.servlet.jsp.tagext不存在 maven打包报程序包javax.servlet.jsp.tagext不存在或者maven打包报程序包javax.servlet.jsp不存 ...
- Python数据分析(一)pandas数据切片
1.获取行或列数据 loc——通过行标签索引行数据 iloc——通过行号索引行数据 ix——通过行标签或者行号索引行数据(基于loc和iloc 的混合) 同理,索引列数据也是如此! import pa ...
- Git 删除服务器的远程分支
git push origin :分支名 可能会出现,在A机子操作,刷新下成功删除,但在B机子上还显示,再用下命令提示不存在该分支,只要再推送一个任意分支即可正常显示