路由系统
1 代码演示 2 3 from flask import Flask 4 5 app = Flask(__name__) 6 7 app.debug = True 8 # 路由基本使用 9 # @app.route('/', methods=['GET']) 10 # @app.get() 11 # @app.post() 12 def index(name): 13 print(name) 14 return 'hello world' 15 16 17 # 自己注册路由,看route源码,等同于django的path 18 app.add_url_rule('/index', endpoint=None, view_func=index, methods=['GET'],defaults={'name': 'zhangsan'}) 19 20 if __name__ == '__main__': 21 app.run() 22 23 ''' 24 route()源码解析,本质 25 使用的时候@app.route('/', methods=['GET'])---decorator---index=decorator(index) 26 def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: 27 def decorator(f: T_route) -> T_route: 28 # 1.如果没有传endpoint,那么就是None 29 endpoint = options.pop("endpoint", None) 30 # 2.self app对象,是Flask类的实例---flask类中的add_url_rule方法方法是路由的本质 31 self.add_url_rule(rule, endpoint, f, **options) 32 return f 33 return decorator 34 于是注册路由,我们可以不用装饰器,可以自己写 35 ''' 36 37 38 ------------------------------------------------------------------------------------ 39 40 # 2 route的参数,其实就是add_url_rule的参数 41 # rule, URL规则,路径 42 # view_func, 视图函数名称 43 # defaults = None, 默认值, 当URL中无参数,函数需要参数时,使用defaults = {'k': 'v'}-为函数提供参数 ---》django中也有,叫kwargs 44 # endpoint = None, 名称[别名],用于反向生成URL,即: url_for('名称') 45 # methods = None, 允许的请求方式,如:["GET", "POST"] 46 # strict_slashes = None 对URL最后的 / 符号是否严格要求 47 ''' 48 @app.route('/index', strict_slashes=False) 49 #访问http://www.xx.com/index/ 或http://www.xx.com/index均可 50 @app.route('/index', strict_slashes=True) 51 #仅访问http://www.xx.com/index 52 ''' 53 # redirect_to = None重定向到指定地址 54 ''' 55 @app.route('/index/<int:nid>', redirect_to='/home/<nid>') 56 ''' 57 58 # subdomain = None子域名访问 59 60 61 62 63 # 3 转换器 app.add_url_rule('/index/<int:pk>') 64 DEFAULT_CONVERTERS = { 65 'default': UnicodeConverter, 66 'string': UnicodeConverter, 67 'any': AnyConverter, 68 'path': PathConverter, 69 'int': IntegerConverter, 70 'float': FloatConverter, 71 'uuid': UUIDConverter, 72 }
。
。
。
偏函数
1 from functools import partial # 内置的 2 3 4 def add(x, y, z): 5 return x + y + z 6 7 8 res = add(1, 2, 3) 9 print(res) 10 11 # 偏函数 12 add_1 = partial(add, 1) # 提前传值 13 print(add_1(2, 3)) 14 15 16 17 后期去找资料文档再补充
。
。
CBV 基于类的视图
基本使用
1 from flask import Flask, url_for 2 from flask.views import MethodView 3 4 app = Flask(__name__) 5 app.debug = True 6 7 8 class IndexView(MethodView): 9 def get(self): 10 return 'get请求' 11 12 def post(self): 13 return 'post请求' 14 15 16 # name其实就是endpoint的别名,且必须传,如果都传,以endpoint为准 17 # app.add_url_rule('/index', endpoint='index', view_func=IndexView.as_view(name='jh')) 18 19 app.add_url_rule('/index', view_func=IndexView.as_view(name='jj')) 20 if __name__ == '__main__': 21 app.run()
源码分析
1 # 0 app.add_url_rule('/index', view_func=IndexView.as_view(name='jh')) 2 3 # 1 as_view 源码 4 @classmethod 5 def as_view(cls, name, *class_args) : 6 if cls.init_every_request: 7 def view(**kwargs: t.Any) -> ft.ResponseReturnValue: 8 self = view.view_class( # type: ignore[attr-defined] 9 *class_args, **class_kwargs 10 ) 11 # current_app.ensure_sync 不用看 12 # 当成 return self.dispatch_request(**kwargs) 13 return current_app.ensure_sync(self.dispatch_request)(**kwargs) 14 else: 15 self = cls(*class_args, **class_kwargs) 16 def view(**kwargs: t.Any) -> ft.ResponseReturnValue: 17 return current_app.ensure_sync(self.dispatch_request)(**kwargs) 18 if cls.decorators: 19 # 把view的名字改为 传入的name,否则它一直叫view--》endpoint没传,就报错 20 # view.__name__ = name 21 for decorator in cls.decorators: 22 view = decorator(view) 23 view.__name__ = name 24 return view 25 26 # 2 变成了 app.add_url_rule('/index', view_func=view) ,view的名字是传入的name 27 28 # 3 请求来了--》执行view()--->有没有参数取决于谁?有没有转换器,有没有defaults 29 30 # 4 执行view本质在执行 self.dispatch_request()--> self是 视图类的对象 31 32 # 5 MethodView 的dispatch_request 33 def dispatch_request(self, **kwargs: t.Any) -> ft.ResponseReturnValue: 34 # 如果是get请求,meth 就是 get方法 35 meth = getattr(self, request.method.lower(), None) 36 # 执行get加括号---》跟django没有区别 37 return meth(**kwargs)
。
。
模板
1 代码示例: 2 3 from flask import Flask, url_for,request 4 from flask.views import MethodView, View 5 6 app = Flask(__name__) 7 app.debug = True 8 9 10 class IndexView(MethodView): 11 def get(self): 12 return 'get请求' 13 14 def post(self): 15 return 'post请求' 16 17 18 class GoodView(View): 19 def dispatch_request(self): 20 if request.method == 'GET': 21 return self.login() 22 23 def login(self): 24 return 'login' 25 26 27 # name其实就是endpoint的别名,且必须传,如果都传,以endpoint为准 28 # app.add_url_rule('/index', endpoint='index', view_func=IndexView.as_view(name='jh')) 29 30 app.add_url_rule('/index', view_func=IndexView.as_view(name='jj')) 31 app.add_url_rule('/login', view_func=GoodView.as_view(name='login')) 32 if __name__ == '__main__': 33 app.run() 34 35 ------------------------------------------------------------------------------ 36 # 1 前后端混合才用 37 38 # 2 django的dtl,拿到这直接可以用 39 -区别在有的函数不一样:过滤器,标签 |safe 40 -if for 41 -取字典,取列表 都完全一样 42 -include 43 -extends 44 45 # 3 比dtl多的 46 - 函数可以加括号---》就能传参数
。
。
请求响应
1 from flask import Flask, url_for, request 2 from flask.views import MethodView, View 3 4 app = Flask(__name__) 5 app.debug = True 6 7 8 class IndexView(MethodView): 9 def get(self): 10 # 请求对象 11 # request.method 提交的方法 12 print(request.args) # get请求提及的数据 http://127.0.0.1:5000/index?name=66 13 # request.form post请求提交的数据 14 # request.values post和get提交的数据总和,,在postman中测,数据放在body内 15 # request.cookies 客户端所带的cookie 16 # request.headers 请求头 17 # request.path 不带域名,请求路径 18 # request.full_path 不带域名,带参数的请求路径 19 # request.script_root 20 # request.url 带域名带参数的请求路径 21 # request.base_url 带域名请求路径 22 # request.url_root 域名 23 # request.host_url 域名 24 # request.host 127.0.0.1:500 25 # request.files 26 # obj = request.files['the_file_name'] 27 # obj.save('/var/www/uploads/' + secure_filename(f.filename)) 28 return 'get请求' 29 30 def post(self): 31 return 'post请求' 32 33 34 app.add_url_rule('/index', view_func=IndexView.as_view(name='jj')) 35 36 if __name__ == '__main__': 37 app.run() 38 39 40 ------------------------------------------------------------------------- 41 响应 42 43 from flask import Flask, url_for, request,make_response,jsonify 44 from flask.views import MethodView, View 45 46 app = Flask(__name__) 47 app.debug = True 48 49 50 class IndexView(MethodView): 51 def get(self): 52 # 1 新手四件套:字符串,模板,重定向,json 53 # 2 向cookie中写入数据 54 res=make_response('get请求') # make_response 放四件套之一都可 55 res.set_cookie('key','lqz',httponly=True,path='/') 56 # 3 向响应头中写入数据 57 res.headers['xxxx']='sss' 58 return res 59 60 def post(self): 61 return 'post请求' 62 63 64 65 app.add_url_rule('/index', view_func=IndexView.as_view(name='lqz')) # 66 if __name__ == '__main__': 67 app.run()
session
1 基本使用 2 3 from flask import Flask, url_for, request, session 4 from flask.views import MethodView, View 5 6 app = Flask(__name__) 7 app.debug = True 8 app.secret_key = 'abscdeklx' 9 10 11 @app.get('/') 12 def index(): 13 # 写入session 14 name = request.args.get('name') 15 session['name'] = name 16 return '写入session成功' 17 18 19 @app.get('/home') 20 def home(): 21 # 读取session 22 name = session.get('name') # 取值 23 # session.pop('name') 删除 24 # session.clear() 清空 25 return 'session中的name是:%s' % name 26 27 28 if __name__ == '__main__': 29 app.run()
不同浏览器再打开设置值取值,都不一样,不互相影响
# 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")
其他参数
# 1 虽然操作session,本质还是以cookie形式保存到浏览器中了
-过期时间,httponly
-配置文件配置
。
。
请求扩展
1 # 1 flask中叫请求扩展---》本质作用实现像django中间件的作用一样 2 3 # 2 flask也有中间件,但是一般不用,用请求扩展即可 4 5 # 3 常用的 6 1 before_request 7 2 after_request 8 3 teardown_request 9 4 errorhandler 10 11 12 # 4 案例 13 ''' 14 # 1 before_request : 15 1 请求来进视图函数之前执行 16 2 多个会从上往下依次执行 17 3 如果返回None,表示继续下一个 18 4 如果返回了四件套:表示结束,不继续往后走 19 ''' 20 21 @app.before_request 22 def before01(): 23 print('来了老弟1') 24 # 向请求对象中,放值 25 request.name='lqz' 26 27 @app.before_request 28 def before02(): 29 print('来了老弟2') 30 31 32 ''' 33 # 1 after_request : 34 1 视图函数执行完,走 35 2 多个会从下往上依次执行 36 3 必须有返回值,是响应对象 37 4 处理跨域,再响应头中加--》就用它 38 ''' 39 @app.after_request 40 def after01(response): 41 print('走了老弟1') 42 return response 43 @app.after_request 44 def after01(response): 45 print('走了老弟2') 46 response.headers['ssss']='sss' 47 return response 48 49 50 ''' 51 teardown_request 52 -1 无论视图函数执行成功或失败,都会走它 53 -2 即便视图函数执行出异常,也会走 54 -3 一般用来记录日志 55 ''' 56 @app.teardown_request 57 def teardown(exc): 58 # exc是视图函数错误对象--》记录错误日志 59 print(exc) 60 61 62 ''' 63 errorhandler 64 -1 监听http响应状态码 65 -2 全局异常处理 66 67 ''' 68 @app.errorhandler(404) 69 def error_404(arg): 70 return jsonify({'code':'xxx'}) 71 @app.errorhandler(500) 72 def error_500(arg): 73 return jsonify({'code':'500错误了'})
1 案例 2 3 from urllib import request 4 5 from flask import Flask 6 7 app = Flask(__name__) 8 app.debug = True 9 10 11 # before_request:请求来进视图函数之前执行 12 @app.before_request 13 def before01(): 14 print('来啦') 15 request.name = '张三' 16 17 18 @app.before_request 19 def before02(): 20 print('来啦2') 21 22 23 @app.get('/') 24 def index(): 25 print(request.name) 26 return '成功' 27 28 29 if __name__ == '__main__': 30 app.run()