flask路由、模板、请求响应、session
目录
一 路由系统
# 1 flask路由系统是基于装饰器的:参数如下
# 2 转换器:
# 3 路由系统本质
# 4 endpoint 不传会怎么样,不传会以视图函数的名字作为值,但是如果加了装饰器,所有视图函数名字都是inner,就会出错,使用wrapper装饰器再装饰装饰器
1.1 flask路由系统的参数
# 1 flask路由系统是基于装饰器的:参数如下
# rule:路径
# methods :请求方式,列表
# endpoint: 路径别名
from flask import Flask
app = Flask(__name__)
@app.route('/detail/<int:nid>',methods=['GET'],endpoint='detail')
def index(name):
print(name)
return 'hello world'
1.2 转换器(了解)
'default': 使用自定义的转换器进行匹配。
'string': 默认的转换器,匹配除斜杠之外的任何字符串。
'any': 匹配给定的选项之一。
'path': 匹配包括斜杠在内的任何文本。
'int': 将值转换为整数
'float': 将值转换为浮点数。
'uuid': 匹配UUID字符串。
# 重点:string int path
from flask import Flask
app = Flask(__name__)
# @app.route('/detail/<int:nid>',methods=['GET'],endpoint='detail')
# @app.route('/<path:aa>', methods=['GET'])
@app.route('/<aa>', methods=['GET']) # default可以不写,后面路径中只能带一个/
def index(name):
print(name)
return 'hello world'
1.3 路由系统本质-->读源码
# 1 点击route进去看源码
@app.route('/<aa>', methods=['GET']) # 本质:index=app.route('/<aa>', methods=['GET'])(index)--->index=decorator(index)
def index(name):
print(name)
return 'hello world'
# 2 Scaffold类的route方法 ---> 返回decorator函数内存
class Scaffold:
@setupmethod
def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]:
def decorator(f: T_route) -> T_route:
endpoint = options.pop("endpoint", None) # 从options弹出,如果没有,就是None --->@app.route(传了就有,不传就是None)
'''核心'''
self.add_url_rule(rule, endpoint, f, **options)
return f # f 就是视图函数,没有对视图函数做事情,只是在执行视图函数之前,加了点操作,调用f,还是之前的f
return decorator
class Scaffold:
def route(self, rule, **options):
def decorator(f):
endpoint = options.pop("endpoint", None) # 从options弹出,如果没有,就是None --->@app.route(传了就有,不传就是None)
'''核心'''
self.add_url_rule(rule, endpoint, f, **options)
return f # f 就是视图函数,没有对视图函数做事情,只是在执行视图函数之前,加了点操作,调用f,还是之前的f
return decorator
# 核心
'''
self.add_url_rule(rule, endpoint, f, **options)
'''
self.add_url_rule(rule, endpoint, f, **options) # --->self就是app对象
<==> app.add_url_rule('路由地址', '路由别名', 视图函数, **options)--->跟django很像
就可以改造为:
def index():
return 'hello world'
def home():
return 'home'
app.add_url_rule('/', 'index', index)
app.add_url_rule('/home', 'home', home)
# add_url_rule的参数详解
-rule, URL规则,路径地址
-view_func, 视图函数名称
-defaults = None, 默认值, URL中无参数,函数需要参数时,使用defaults = {'k': 'v'}为函数提供参数
-endpoint = None, 名称,用于反向生成URL,即: url_for('名称')
-methods = None, 允许的请求方式,如:["GET", "POST"]
-strict_slashes = None # 对URL最后的 / 符号是否严格要求
-redirect_to = None, # 重定向到指定地址
def index(name):
print(name)
return 'hello world'
def home():
return 'home'
app.add_url_rule('/', 'index', index,defaults={'name':'lqz'}) # django讲media中
app.add_url_rule('/home', 'home', home,strict_slashes=True,redirect_to = '/')
1.4 endpoint
# endpoint 不传会怎么样,不传会以视图函数的名字作为值,但是如果加了装饰器,所有视图函数名字都是inner,就会出错,使用wrapper装饰器再装饰装饰器
from flask import Flask
app = Flask(__name__)
@app.route('/', methods=['GET'])
def index(name):
print(name)
return 'hello world'
def home():
return 'home'
if __name__ == '__main__':
app.run()
1.5 flask写接口api
# 使用Flask-Restful插件:
https://www.cnblogs.com/donghaoblogs/p/10389696.html
二 CBV
1 cbv写法
-1 写个类,继承MethodView
-2 在类中写跟请求方式同名的方法
-3 注册路由:app.add_url_rule('/home', view_func=Home.as_view('home')) #home是endpoint,就是路由别名
2 cbv加装饰器
-方式一:
class Home(MethodView):
decorators = [auth] # 之前加载fbv上的,直接拿过来用即可
-方式二:
class Home(MethodView):
@auth # 这个auth需要单独写,跟加载fbv上的不一样
def get(self):
return render_template('home.html')
3 允许的请求方式
class Home(MethodView):
methods = ['GET'] # 控制能够允许的请求方式
4 cbv源码
5 为什么decorators = [auth] 能加装饰器
app.add_url_rule('/home', view_func=view内存地址)
用装饰器一直在装饰 view内存地址 ,所以,以后执行,就是有装饰器的view,装饰器代码会走
@auth
def view(**kwargs):
return self.dispatch_request(**kwargs)
等价于
view = auth(view)
6 view_func=Home.as_view('home') home 是 endpoint,就是路由别名
-1 app.add_url_rule('/home', view_func=Home.as_view('home'))
-2 add_url_rule--->endpoint没传--->会执行endpoint = _endpoint_from_view_func(view_func)
-3 取函数名作为 endpoint 的值
-4 view_func是 加了一堆装饰器的view函数--->它的名字应该是装饰器的名字-->但是
view.__name__ = name # name 就是home
-5 所以endpoint就是你传的home
-6 如果传了endpoint,就是传的那个,那as_view('home')就没作用了,但是也必须要传
# 基于类的视图
from flask import Flask, render_template
# app = Flask(__name__,template_folder='templates')
app = Flask(__name__)
app.debug = True
def auth(func):
def inner(*args, **kwargs):
print('我执行了')
ret = func(*args, **kwargs)
return ret
return inner
# FBV:基于函数的视图
@app.route('/')
@auth
def index():
return 'hello'
# cbv:基于类的视图 继承MethodView--->View
from flask.views import View, MethodView
# 1 写个类继承
class Home(MethodView):
decorators = [auth] # 如果有多个装饰器,使用 , 继续拼接即可
methods = ['GET'] # 控制能够允许的请求方式
def get(self):
return render_template('home.html')
def post(self):
return '我是post'
# 2 注册路由
app.add_url_rule('/home', view_func=Home.as_view('home'))
if __name__ == '__main__':
app.run(port=8080)
2.2 as_view源码
# View的as_view
@classmethod
def as_view(cls, name, *class_args, **class_kwargs) :
def view(**kwargs):
return self.dispatch_request(**kwargs)
if cls.decorators: # 咱们的装饰器
view.__name__ = name
view.__module__ = cls.__module__
for decorator in cls.decorators: #每次拿出一个装饰器,
view = decorator(view) # 装饰器语法糖干的事: 把被装饰的函数当参数传入到装饰器,返回结果赋值给被装饰的函数,一个个用装饰器包装view
view.__name__ = name
return view
# self.dispatch_request--->MethodView
def dispatch_request(self, **kwargs) :
# 取到request.method.lower()请求方式小写 --->假设是get请求get
# meth是 cbv中 以get命名的方法,反射出来了
meth = getattr(self, request.method.lower(), None)
return meth(**kwargs) # 执行cbv中跟请求方式同名的方法
三 模板
# 之前dtl中学的所有知识,拿到这,都可以用--->dtl是django自己的,不能独立使用
# jinja2 模板语法,第三方,flask使用了它,它可以单独使用
# jinja2 模板语法 支持括号调用,支持 字典[] 取值---->模板中写原来python的语法都支持
# jinja2模板语法处理了xss攻击
django,jinja2处理xss攻击原理是?
-使用了html特殊字符的替换,把字符串中得 < > 都用特殊字符替换
# extends,include
# 基于类的视图
from flask import Flask, render_template,Markup
app = Flask(__name__)
app.debug = True
@app.route('/')
def index():
s = Markup("<input type='text' value='姓名'/>") # 直接使用
# s = "<input type='text' value='姓名'/>" 模板中使用{{s|safe}}
a=10
return render_template('index.html',s=s,a=a)
if __name__ == '__main__':
app.run()
四 请求响应
# 所有web:请求对象,响应对象(go,java,ptyhon)
django:request(每个请求一个request),新手四件套
flask:requset:全局的,但是也是每个请求一个request,新手三件套
# flask请求对象,全局的request
# 请求相关信息
# request.method 请求的方法
# request.args get请求提交的数据
# request.form post请求提交的数据
# request.values post和get提交的数据总和
# request.cookies 客户端所带的cookie
# request.headers 请求头
# request.path 不带域名,请求路径
# request.full_path 不带域名,带参数的请求路径
# request.url 带域名带参数的请求路径
# request.base_url 带域名请求路径
# request.url_root 域名
# request.host_url 域名
# request.host 服务端地址
# request.files
# obj = request.files['the_file_name']
# obj.save('/var/www/uploads/' + secure_filename(f.filename))
# flask的响应
-四件套:
-1 直接返回字符串
-2 返回模板:render_template
-3 返回重定向:redirect,
-4返回json格式:jsonify
-响应中写cookie
res = make_response('home')
res.set_cookie('yyy', 'yyy', path='/home')
# 删除cookie
# res.delete_cookie('key')
-响应头中写内容
res = make_response('home') # res 就是响应对象
res.headers['xxx'] = 'xxx'
from flask import Flask, request, render_template, redirect, jsonify, make_response
app = Flask(__name__)
app.debug = True
@app.route('/', methods=['POST', 'GET'])
def index():
# 在哪个里面执行代码,这个request代指的就是谁的request
# print(request.path)
# test()
# print(request.values)
# print(request.path)
# print(request.full_path)
print(type(request.files.get('myfiles')))
with open('xx.zip', 'wb') as f:
for line in request.files.get('myfiles'):
f.write(line)
# from werkzeug.datastructures.file_storage import FileStorage
return 'hello'
@app.route('/home')
def home():
# 在哪个里面执行代码,这个request代指的就是谁的request
print(request.path)
test()
# return jsonify({'name': 'lqz', 'age': 19})
# return jsonify([{'name': 'lqz', 'age': 19},{'name': 'lqz', 'age': 19}])
# return jsonify({'code': 100, 'msg': '成功', 'data': []})
# 往响应头写数据
res = make_response('home') # res 就是响应对象
res.headers['xxx'] = 'xxx'
# 往cookie中写数据
res.set_cookie('yyy', 'yyy', path='/home')
# 删除cookie
# res.delete_cookie('key')
return res
def test():
print(type(request.args))
# from werkzeug.datastructures.structures import ImmutableMultiDict
print(request.args) # get请求的参数
if __name__ == '__main__':
app.run()
五 session
# cookie session token
# flask中得session,没有在服务端存储数据的--->后期扩展,可也把session存到redis中
# 全局session
-放值:session['key']=value
-取值:session.get('key')
-删除值:session.pop('username', None)
# session的运行机制
'''
django
1 生成一个随机字符串
2 把数据保存到djagno-session表中
3 把随机字符串返回给前端-->当cookie存到浏览器中了-->浏览器再发请求,携带cookie过来
4 根据随机字符串去表中查--->转到request.session中
flask
1 把数据加密转成字符串: eyJuYW1lIjoibHF6In0.ZMnbJw.ZUceSaD0kGnU97tu9ZWm3380r00
2 以cookie形式返回给前端--->保存到浏览器中
3 浏览器再发请求,携带cookie过来
4 加密符串--->解密--->放到session对象中
'''
# 源码分析,看运行机制
-flask默认使用:SecureCookieSessionInterface作为session的类
-请求来了,
-客户端带了cookie--->取出cookie 中session对应的值
-使用解密方式对它进行解密
-放到session对象中
-请求走了
-把用户放到session中得数据
-加密--->转成字符串-->以cookie形式返回给前端
-SecureCookieSessionInterface的方法e:
-open_session:请去来了用
-save_session:请求走了用
from flask import Flask, session
app = Flask(__name__)
app.debug = True
app.secret_key = 'asdfasdfasdasdf'
app.session_interface
@app.route('/', methods=['POST', 'GET'])
def index():
session['name'] = 'lqz'
session['age'] = 19
return 'hello'
@app.route('/home')
def home():
print(session.get('name'))
return 'home'
if __name__ == '__main__':
app.run()