flask_day02:cbv 模板语法 请求与响应 session 闪现flash 请求扩展before_request

cbv分析

基于类的视图,写法

# 基于类的视图,写法

from flask import Flask,request
from flask.views import View, MethodView

app = Flask(__name__)

app.debug = True


# 视图类,继承MethodView,类中写跟请求方式同名的方法即可,之前学的所有都一致
class IndexView(MethodView):
    def get(self):
        print(request.method)
        return 'get 请求'

    def post(self):
        print(request.method)
        return 'post 请求'


app.add_url_rule('/index', endpoint='index', view_func=IndexView.as_view('index'))
if __name__ == '__main__':
    app.run()

源码分析

1 IndexView.as_view('index') 执行完的结果,是个函数(view的)内存地址
    def as_view(cls, name, *class_args, **class_kwargs):
        def view(**kwargs: t.Any) -> ft.ResponseReturnValue:
            # 本质是在执行self.dispatch_request,只是用了异步
           return current_app.ensure_sync(self.dispatch_request)(**kwargs)
        return view
    
    
2 请求来了,执行view()--->本质在执行self.dispatch_request---》MethodView中的
    def dispatch_request(self, **kwargs):
        # self是视图类的对象
        meth = getattr(self, request.method.lower(), None)
        # 用异步执行meth()
        return current_app.ensure_sync(meth)(**kwargs)
    
    
3 总结:执行原理跟django一样


4 路径如果不传别名,别名就是函数名---》分析一下源码
	-@app.route('/index')--》没有传endpoint
    -endpoint 就是None---》调用了app.add_url_rule,传入了None
    if endpoint is None:
       endpoint = _endpoint_from_view_func(view_func)  # type: ignore
	-_endpoint_from_view_func 就是返回函数的名字
5 as_view('index') 必须传参数,传进来的参数是,是【别名】
	# view是as_view内的内层函数,闭包函数
	view.__name__ = name  # 修改了函数的名字变成了你传入的
    
    # app.add_url_rule('/index',view_func=IndexView.as_view('index'))
    简写成:app.add_url_rule('/index',view_func=view)
    #如果不传参数, 所有人的别名(endpoint),都是内层函数view,所以就报错了
    
    
   

6 补充:flask的路由注册使用装饰器,如果写了一个登录认证装饰器,那么应该放在路由装饰器上还是下?
	-放在路由下面
    -路由必须传endpoint,如果不传,又报错

    
    
7  视图类必须继承MethodView,如果继承View,它的dispatch_request没有具体实现,你的视图类必须重写dispatch_request,我们不想重写,继承MethodView
    def dispatch_request(self) -> ft.ResponseReturnValue:
        raise NotImplementedError()
    
    
8 视图类加装饰器,直接配置在类属性上【decorators】即可
	decorators = [auth,]
    # 源码,cls是视图类,中有decorators
    if cls.decorators:
      for decorator in cls.decorators:
          view = decorator(view)  # view=auth(view)  

源码学到的

-1 as_view 执行流程跟djagno一样
-2 路径如果不传别名,别名就是函数名(endpoint)
-3 视图函数加多个装饰器(上下顺序和必须传endpoint)
-4 视图类必须继承MethodView,否则需要重写dispatch_request
-5 视图类加装饰器:类属性decorators = [auth,]

image-20230403201805486

模板

py文件中

from flask import Flask, render_template,Markup

app = Flask(__name__, template_folder='templates', static_folder='static')  # 模板的路径必须是templates,因为实例化app对象时,传入的
app.debug=True


def add(a,b):
    return a+b
@app.route('/')
def index():
    a='<a href="http://www.baidu.com">点我看美女</a>'  # 不存在xss攻击,处理了xss
    a=Markup(a)
    return render_template('index.html',name='lqz',a=a,add=add)


if __name__ == '__main__':
    app.run()

例化app对象时,传入的

image-20230403214001957

image-20230403210233667

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>模板语法,static</h1>
<img src="/static/1.jpg" alt="">

<h1>模板语法,if</h1>
{% if name %}
<h1>Hello {{ name }}!</h1>
{% else %}
<h1>Hello World!</h1>
{% endif %}

<h1>模板语法,标签渲染</h1>
{{a|safe}}
{{a}}

<h1>模板语法,执行函数</h1>
{{add(4,5)}}

</body>
</html>

模板语法标签渲染

image-20230403213752195

请求与响应

请求:全局的request对象,render_template,redirect,jsonfiy,retun 字符串

响应:四件套

from flask import Flask, request, make_response,render_template

app = Flask(__name__)
app.debug = True


@app.route('/', methods=['GET', 'POST'])
def index():
    #### 请求
    # 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
    print(request.method)
    print(request.args)
    print(request.form)
    print(request.values)
    print(request.cookies)
    print(request.headers)
    print(request.path)
    print(request.full_path)
    print(request.url)
    print(request.base_url)
    print(request.host_url)
    print(request.host)

    obj = request.files['file']
    obj.save(obj.filename)

    ### 响应  四件套
    # 1 响应中写入cookie
    # response = 'hello'
    # res = make_response(response)  # flask.wrappers.Response
    # print(type(res))
    # res.set_cookie('xx','xx')
    # return res
    # 2 响应头中写数据(新手四件套,都用make_response包一下)
    response = render_template('index.html')
    res = make_response(response)  # flask.wrappers.Response
    print(type(res))
    res.headers['yy']='yy'
    return res


if __name__ == '__main__':
    app.run()

image-20230403220855073

headers中key、value的形式存储

image-20230403215242098

打印结果:

image-20230403220618220

响应头中写数据

image-20230403223332528

session及源码分析

session的使用

from flask import Flask, request, session, render_template, redirect

app = Flask(__name__)
app.debug = True
app.secret_key = 'asdfas33asdfasf'


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        return render_template('login.html')
    else:
        name = request.form.get('name')
        password = request.form.get('password')
        print(password)
        session['name'] = name
        return redirect('/index')


@app.route('/index', methods=['GET', 'POST'])
def index():
    return 'hello %s' % session.get('name', '匿名用户')

if __name__ == '__main__':
    app.run()

image-20230403113351106

而http每一次请求都是新的,但这里用session的机制就能每次都拿到上次的session,这是flask框架内部做的事。

源码分析

cookie :存在于客户端浏览器的键值对

session:存在于服务端的键值对

# cookie :存在于客户端浏览器的键值对
# session:存在于服务端的键值对    # djagno 放在了django_session表中

# flask中,叫session,问题来了,存哪里呢?
	-加密后,放到了cookie中,如果session发生了变化,我们的cookie也会跟着变  --->>> 所以要指定secret_key
    

    
# 源码部分:
	# 1 app.session_interface  配置了一个类的对象,这个就是session的执行流程
    # 2 类中有两个非常重要的方法,请求来了,会执行open_session,请求走了会执行save_session
      def open_session(self, app, request) :
		#1 根据名字,取出前端传入的cookie的value值
        val = request.cookies.get(self.get_cookie_name(app))
        #2 如果没有val,构造了一个空session对象
        if not val:
            return self.session_class()
        max_age = int(app.permanent_session_lifetime.total_seconds())
        try:
            # 如果没有过期,解码,做成session对象,后续直接用session即可
            data = s.loads(val, max_age=max_age)
            return self.session_class(data)
        except BadSignature:
            # 如果过期了,也是空session
            return self.session_class()
        
        


    def save_session(self, app, session, response) :
        name = self.get_cookie_name(app)
		# 取出过期事件,和把session加密转成字符串,放到cookie中
        expires = self.get_expiration_time(app, session)
        val = self.get_signing_serializer(app).dumps(dict(session))
        response.set_cookie(
            name,
            val, 
            expires=expires,
        )
        
        
        
        
  # 扩展,想把session放到redis中,mysql中,已经有人帮咱们写了,第三方的
	只需要写个类,重写open_session,save_session自己写

session是在全局取的,但是不同浏览器中取的都是不一样的

image-20230403224345972

闪现flash

跨请求来存数据,取一次就没了。能通过浏览器自动区分,因为是将值放在session中了

# flash 翻译过来的
	- 当次请求先把一些数据,放在某个位置
    - 下一次请求,把这些数据取出来,取完,就没了
    
# 作用:
1 可以跨请求,来保存数据
2 当次请求,访问出错,被重定向到其他地址,重定向到这个地址后,拿到当时的错误
    
    
# djagno中有这个东西吗?
	-message框架
# 用法:
	-设置 闪现  
    	-flash('%s,我错了'%name) ,可以设置多次,放到列表中
      -flash('超时错误',category="debug") 分类存 
 	-获取 闪现
    	-get_flashed_messages() ,取完就会自动删除
    	-get_flashed_messages(category_filter=['debug'])分类取
        
        
        
 # 本质,放到session中

image

请求扩展

请求扩展中:在请求来了,或请求走了,可以绑定一些函数,到这里就会执行这个函数,类似于django的中间件

在flask中就用请求扩展,来代替Django的中间件

# 好几个请求扩展
-before_request:请求来了会走,如果他返回了四件套,就结束了
-after_request :请求走了会走,一定要返回response对象
-before_first_request:第一次来了会走
-teardown_request:无论是否出异常,会走
-errorhandler:监听状态码,404  500

-template_global:标签
-template_filter:过滤器

总结:

1、重点掌握before_request和after_request,

2、注意有多个的情况,执行顺序

3、before_request请求拦截后(也就是有return值),response所有都执行

代码

from flask import Flask, request,render_template

app = Flask(__name__)


1 before_request 和 after_request
# 请求来了,执行一个函数,来的时候从上往下执行
# @app.before_request
# def before():
#     print('我来了111')
#     # if 'index' in request.path:
#     return '不让看了'  # 如果不是retrun了None,说明被拦截了,直接返回
#
#
# @app.before_request
# def before1():
#     print('我来了222')
#
#
# # 请求走了,执行一个函数,走的时候,从下往上执行
# @app.after_request
# def after(response):
#     print('我走了111')
#     return response
#
#
# @app.after_request
# def after2(response):
#     print('我走了222')
#     return response

执行结果就是:我来了111、我走了222、我走了111


2 项目启动后的第一个请求
# @app.before_first_request
# def first():
#     print('我的第一次')


3 teardown_request,无论视图函数是否出错,都会执行它,做错误日志
# @app.teardown_request
# def teardown(e):
#     print(e)
#     print('执行我了')



4 errorhandler  监听响应状态码,如果符合监听的状态码,就会走它
# @app.errorhandler(404)
# def error_404(arg):
#     return "404错误了"

# @app.errorhandler(500)
# def error_500(arg):
#     return "500错误了"


##5 template_global  在模板中直接使用该过滤器
@app.template_global()
def add(a1, a2):
    return a1 + a2

# 6 template_filter
@app.template_filter()
def db(a1, a2, a3):
    return a1 + a2 + a3


@app.route('/')
def index():
    # a = [1, 2, 3]
    # print(a[9])
    return render_template('index1.html')


if __name__ == '__main__':
    app.run()

posted @   小福福  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
  1. 1 原来你也在这儿 温余福
  2. 2 世间美好和你环环扣扣 温余福
  3. 3 随风起舞 温余福
  4. 4 罪恶都市 温余福
随风起舞 - 温余福
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : 米果

作曲 : 高橋優

编曲 : 刘胡轶/貢多杰

制作人 : 刘胡轶/吴青峰

配唱制作人 : 刘胡轶

乐器监制 : 刘胡轶

吉他 : 胡晨

贝斯 : 甯子达

弦乐录音棚 : 中国剧院录音棚

录音工程师 : 倪涵文/李游/李杨/邢铜/韩宽/李巍

录音监制 : 倪涵文/李游

混音&母带工作室 : OKmastering studio

混音&母带工程师 : 全相彦

制作协力 : 刘西洋

制作发行 : 智慧大狗 × 天才联盟

出品人 : 张葛

监制 : 崔恕/王明宇

弦乐监制 : 李朋

弦乐 : 国际首席爱乐乐团

鼓(打击乐):祁大为

和音编写&演唱:鱼椒盐

人声&吉他&鼓(打击乐)录音棚:55Tec studio

我曾将青春翻涌成她

我曾将青春翻涌成她

也曾指尖弹出盛夏

心之所动 且就随缘去吧

这一路上走走停停

这一路上走走停停

顺着少年漂流的痕迹

迈出车站的前一刻

竟有些犹豫

不禁笑这近乡情怯

不禁笑这近乡情怯

仍无可避免

而长野的天

依旧那么暖

风吹起了从前

从前初识这世间

从前初识这世间

万般流连

看着天边似在眼前

也甘愿赴汤蹈火去走它一遍

如今走过这世间

如今走过这世间

万般流连

翻过岁月不同侧脸

措不及防闯入你的笑颜

我曾难自拔于世界之大

我曾难自拔于世界之大

也沉溺于其中梦话

不得真假 不做挣扎 不惧笑话

我曾将青春翻涌成她

我曾将青春翻涌成她

也曾指尖弹出盛夏

心之所动 且就随缘去吧

逆着光行走 任风吹雨打

短短的路走走停停

短短的路走走停停

也有了几分的距离

不知抚摸的是故事 还是段心情

也许期待的不过是 与时间为敌

再次看到你

微凉晨光里

笑得很甜蜜

从前初识这世间

从前初识这世间

万般流连

看着天边似在眼前

也甘愿赴汤蹈火去走它一遍

如今走过这世间

如今走过这世间

万般流连

翻过岁月不同侧脸

措不及防闯入你的笑颜

我曾难自拔于世界之大

我曾难自拔于世界之大

也沉溺于其中梦话

不得真假 不做挣扎 不惧笑话

我曾将青春翻涌成她

我曾将青春翻涌成她

也曾指尖弹出盛夏

心之所动 且就随缘去吧

晚风吹起你鬓间的白发

晚风吹起你鬓间的白发

抚平回忆留下的疤

你的眼中 明暗交杂 一笑生花

我仍感叹于世界之大

我仍感叹于世界之大

也沉醉于儿时情话

不剩真假 不做挣扎 无谓笑话

我终将青春还给了她

连同指尖弹出的盛夏

心之所动 就随风去了

以爱之名 你还愿意吗

点击右上角即可分享
微信分享提示