路由系统

 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()

 

posted on 2024-06-14 21:36  认真的六六  阅读(9)  评论(0编辑  收藏  举报