flask进阶使用

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 原理及源码

image-20240612165023909

    # 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()
posted @ 2024-06-27 19:06  -半城烟雨  阅读(1)  评论(0编辑  收藏  举报