1 偏函数partial()
from functools import partial
def add(a,b,c):
return a+b+c
res=add(1,2,3)
print(res)
res=partial(add,1) # 提前传值
print(res(2,3))
2.CBV(类视图)
2.1基本使用
from flask import Flask, url_for
from flask.views import MethodView
app = Flask(__name__)
app.debug = True
class IndexView(MethodView):
def get(self):
return 'get请求'
def post(self):
return 'post请求'
# app.add_url_rule('/index', endpoint='index', view_func=IndexView.as_view(name='hope')) #
app.add_url_rule('/index', view_func=IndexView.as_view(name='hope')) #
# IndexView.as_view(name='hope') 必须传name,而name是路由的别名
# 问?即传了endpoint,又传了name,以谁为准?
if __name__ == '__main__':
app.run()
2.2 问?即传了endpoint,又传了name,以谁为准?
如果传了endpoint,以endpoint 为准
如果没传,以函数名为准,函数名是view,但是被name改了,所以 name为准
# 验证:url_for反向解析试一下
2.3 cbv源码分析
# 0 app.add_url_rule('/index', view_func=IndexView.as_view(name='hope'))
# 1 as_view 源码
@classmethod
def as_view(cls, name, *class_args) :
if cls.init_every_request:
def view(**kwargs: t.Any) -> ft.ResponseReturnValue:
self = view.view_class( # type: ignore[attr-defined]
*class_args, **class_kwargs
)
# current_app.ensure_sync 不用看
# 当成 return self.dispatch_request(**kwargs)
return current_app.ensure_sync(self.dispatch_request)(**kwargs)
else:
self = cls(*class_args, **class_kwargs)
def view(**kwargs: t.Any) -> ft.ResponseReturnValue:
return current_app.ensure_sync(self.dispatch_request)(**kwargs)
if cls.decorators:
# 把view的名字改为 传入的name,否则它一直叫view--》endpoint没传,就报错
# view.__name__ = name
for decorator in cls.decorators:
view = decorator(view)
view.__name__ = name
return view
# 2 变成了 app.add_url_rule('/index', view_func=view) ,view的名字是传入的name
# 3 请求来了--》执行view()--->有没有参数取决于谁?有没有转换器,有没有defaults
# 4 执行view本质在执行 self.dispatch_request()--> self是 视图类的对象
# 5 MethodView 的dispatch_request
def dispatch_request(self, **kwargs: t.Any) -> ft.ResponseReturnValue:
# 如果是get请求,meth 就是 get方法
meth = getattr(self, request.method.lower(), None)
# 执行get加括号---》跟django没有区别
return meth(**kwargs)
# 6 自己基于View写视图类
class GoodsView(View):
def dispatch_request(self) :
if request.method == 'GET':
return self.login()
def login(self):
return 'login'
app.add_url_rule('/login', view_func=GoodsView.as_view('denglu'))
if __name__ == '__main__':
app.run()
3 模板
# 1 前后端混合才用
# 2 django的dtl,拿到这直接可以用
-区别在有的函数不一样:过滤器,标签 |safe
-if for
-取字典,取列表 都完全一样
-include
-extends
# 3 比dtl多的
- 函数可以加括号---》就能传参数
4 请求响应
4.1 请求对象
# request.method 提交的方法
# request.args get请求提及的数据
# request.form post请求提交的数据
# request.values post和get提交的数据总和
# request.cookies 客户端所带的cookie
# request.headers 请求头
# request.path 不带域名,请求路径
# request.full_path 不带域名,带参数的请求路径
# request.script_root
# request.url 带域名带参数的请求路径
# request.base_url 带域名请求路径
# request.url_root 域名
# request.host_url 域名
# request.host 127.0.0.1:500
# request.files
# obj = request.files['the_file_name']
# obj.save('/var/www/uploads/' + secure_filename(f.filename))
4.2 响应对象
from flask import Flask, url_for, request,make_response,jsonify
from flask.views import MethodView, View
app = Flask(__name__)
app.debug = True
class IndexView(MethodView):
def get(self):
# 1 新手四件套:字符串,模板,重定向,json
# 2 向cookie中写入数据
res=make_response('get请求') # make_response 放四件套之一都可
res.set_cookie('key','hope',httponly=True,path='/')
# 3 向响应头中写入数据
res.headers['xxxx']='sss'
return res
def post(self):
return 'post请求'
app.add_url_rule('/index', view_func=IndexView.as_view(name='hope')) #
if __name__ == '__main__':
app.run()
5 session使用
5.1 基本使用
# session['name'] = name
# name = session.get('name')
# session.pop('name')
# session.clear()
5.2 原理及源码
# open_session
def open_session(self, app: Flask, request: Request) -> SecureCookieSession | None:
s = self.get_signing_serializer(app)
if s is None:
return None
val = request.cookies.get(self.get_cookie_name(app))
if not val:
return self.session_class()
max_age = int(app.permanent_session_lifetime.total_seconds())
try:
data = s.loads(val, max_age=max_age)
return self.session_class(data)
except BadSignature:
return self.session_class()
# save_session
def save_session(
self, app: Flask, session: SessionMixin, response: Response
) -> None:
name = self.get_cookie_name(app)
domain = self.get_cookie_domain(app)
path = self.get_cookie_path(app)
secure = self.get_cookie_secure(app)
samesite = self.get_cookie_samesite(app)
httponly = self.get_cookie_httponly(app)
# Add a "Vary: Cookie" header if the session was accessed at all.
if session.accessed:
response.vary.add("Cookie")
# If the session is modified to be empty, remove the cookie.
# If the session is empty, return without setting the cookie.
if not session:
if session.modified:
response.delete_cookie(
name,
domain=domain,
path=path,
secure=secure,
samesite=samesite,
httponly=httponly,
)
response.vary.add("Cookie")
return
if not self.should_set_cookie(app, session):
return
expires = self.get_expiration_time(app, session)
val = self.get_signing_serializer(app).dumps(dict(session)) # type: ignore
response.set_cookie(
name,
val, # type: ignore
expires=expires,
httponly=httponly,
domain=domain,
path=path,
secure=secure,
samesite=samesite,
)
response.vary.add("Cookie")
6 请求扩展
- flask中叫请求扩展---》本质作用实现像django中间件的作用一样
- flask也有中间件,但是一般不用,用请求扩展即可
6.1常用的
1 before_request
2 after_request
3 teardown_request
4 errorhandler
6.2案例
# 1 before_request :
1 请求来进视图函数之前执行
2 多个会从上往下依次执行
3 如果返回None,表示继续下一个
4 如果返回了四件套:表示结束,不继续往后走
@app.before_request
def before01():
print('来了老弟1')
# 向请求对象中,放值
request.name='hope'
@app.before_request
def before02():
print('来了老弟2')
'''
# 1 after_request :
1 视图函数执行完,走
2 多个会从下往上依次执行
3 必须有返回值,是响应对象
4 处理跨域,再响应头中加--》就用它
'''
@app.after_request
def after01(response):
print('走了老弟1')
return response
@app.after_request
def after01(response):
print('走了老弟2')
response.headers['ssss']='sss'
return response
'''
teardown_request
-1 无论视图函数执行成功或失败,都会走它
-2 即便视图函数执行出异常,也会走
-3 一般用来记录日志
'''
@app.teardown_request
def teardown(exc):
# exc是视图函数错误对象--》记录错误日志
print(exc)
'''
errorhandler
-1 监听http响应状态码
-2 全局异常处理
'''
@app.errorhandler(404)
def error_404(arg):
return jsonify({'code':'xxx'})
@app.errorhandler(500)
def error_500(arg):
return jsonify({'code':'500错误了'})
@app.get('/')
def index():
# print(request.name)
l=[1,2]
print(l[3])
return '成功'
app.add_url_rule('/', 'index', index, methods=['GET'])
if __name__ == '__main__':
app.run()