107、CBV、模板、请求响应、session

69 阅读6分钟

今日内容概要

  • CBV
  • 模板
  • 请求响应
  • session

今日内容详细

CBV

cbv写法

1.写个类,继承MethodView
2.在类中写跟请求方式同名的方法
3.注册路由:app.add_url_rule('/home', view_func=Home.as_view('home'))  #home是endpoint,就是路由别名
from flask import Flask
from flask.views import View,MethodView

app = Flask(__name__)
app.debug = True

class Home(MethodView):

    def get(self):
        return 'get'

    def post(self):
        return 'post'

app.add_url_rule('/','Home',Home.as_view('home'))

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

CBV加装饰器

1.方式一:
	class Home(MethodView):
    	decorators = [auth]  # 之前加载fbv上的,直接拿过来用即可
2.方式二:
    class Home(MethodView):
        @auth  # 这个auth需要单独写,跟加载fbv上的不一样
    	def get(self):
        	return render_template('home.html')

方式一





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


app = Flask(__name__)
app.debug = True


def outer(func_name):
    def inner(*args,**kwargs):
        print('执行了')
        res = func_name(*args,**kwargs)
        return res
    return inner

class Home(MethodView):
    decorators = [outer]  # 如果有多个装饰器,使用  , 继续拼接即可


    def get(self):
        return 'get'

    def post(self):
        return 'post'

app.add_url_rule('/','Home',Home.as_view('home'))

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

方式二


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


app = Flask(__name__)
app.debug = True

def outer(func_name):
    def inner(*args,**kwargs):
        print('执行了')
        res = func_name(*args,**kwargs)
        return res
    return inner

class Home(MethodView):
    # decorators = [outer]

    @outer  # 这个outer需要单独写,跟加载fbv上的不一样
    def get(self):
        return 'get'
    @outer
    def post(self):
        return 'post'

app.add_url_rule('/','Home',Home.as_view('home'))

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

允许的请求方式

class Home(MethodView):
  methods = ['GET']  # 控制能够允许的请求方式

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


app = Flask(__name__)
app.debug = True

class Home(MethodView):
    methods = ['POST']  # 控制能够允许的请求方式

    # @outer  # get = outer(get)
    def get(self):
        return 'get'
    # @outer
    def post(self):
        return 'post'

app.add_url_rule('/','Home',Home.as_view('home'))

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

CBV源码

1.入口app.add_url_rule('/','Home',Home.as_view('home'))的as_view()
2.点击as_view()
    def as_view(cls, name, *class_args, **class_kwargs):
        if cls.init_every_request:
            def view(**kwargs) :
                self = view.view_class(  *class_args, **class_kwargs)
                return self.dispatch_request(**kwargs)  # 进入MethodView的dispatch_request()

        if cls.decorators: # 咱们的装饰器
            for decorator in cls.decorators:    # 循环列表
                view = decorator(view)   # 装饰器语法糖干的事: 把被装饰的函数当参数传入到装饰器,返回结果赋值给被装饰的函数,一个个用装饰器包装view
        return view
      
      
3.鼠标进入MethodView的dispatch_request()
    def dispatch_request(self, **kwargs):
     	# 取到request.method.lower()请求方式小写 ---》假设是get请求get
        meth = getattr(self, request.method.lower(), None) #meth是 cbv中 以get命名的方法,反射出来了   
        if meth is None and request.method == "HEAD":
            meth = getattr(self, "get", None)
        assert meth is not None, f"Unimplemented method {request.method!r}"
        return current_app.ensure_sync(meth)(**kwargs)    # 进入方法

为什么decorators = [outer] 能加装饰器

1.app.add_url_rule('/home', view_func=view内存地址)
  用装饰器一直在装饰 view内存地址 ,所以,以后执行,就是有装饰器的view,装饰器代码会走
    @outer
    def view(**kwargs):
        return self.dispatch_request(**kwargs)
    等价于
    view = outer(view)
    

研究endpoint

 1.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.def _endpoint_from_view_func(view_func):
    return view_func.__name__
	3.取函数名作为 endpoint 的值
	4.view_func是 加了一堆装饰器的view函数--->它的名字应该是装饰器的名字-->但是
    	view.__name__ = name  # name 就是home
	5.所以endpoint就是你传的home
	6.如果传了endpoint,就是传的那个,那as_view('home')就没作用了,但是也必须要传

模版

1.之前dtl中学的所有知识,拿到这,都可以用--->dtl是django自己的,不能独立使用
2.jinja2 模板语法,第三方,flask使用了它,它可以单独使用
3.jinja2 模板语法 支持括号调用,支持 字典[] 取值---->模板中写原来python的语法都支持

4.jinja2模板语法处理了xss攻击
5.django,jinja2处理xss攻击原理是?
	使用了html特殊字符的替换,把字符串中得 <  > 都用特殊字符替换
ps:
  1.Markup等价django的mark_safe ,
  2.extends,include一模一样

渲染变量

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>用户列表</h1>
    <table>
        {% for k,v in user_dict.items() %}
        <tr>
            <td>{{k}}</td>
            <td>{{v.name}}</td>
            <td>{{v['name']}}</td>
            <td>{{v.get('name')}}</td>
            <td><a href="/detail/{{k}}">查看详细</a></td>
        </tr>
        {% endfor %}
    </table>
</body>
</html>

变量的循环

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>用户列表</h1>
    <table>
        {% for k,v in user_dict.items() %}
        <tr>
            <td>{{k}}</td>
            <td>{{v.name}}</td>
            <td>{{v['name']}}</td>
            <td>{{v.get('name')}}</td>
            <td><a href="/detail/{{k}}">查看详细</a></td>
        </tr>
        {% endfor %}
    </table>
</body>
</html>

逻辑判断

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>用户列表</h1>
    <table>
        {% if name %}
          <h1>Hello {{ name }}!</h1>
        {% else %}
          <h1>Hello World!</h1>
        {% endif %}
    </table>
</body>
</html>

比django中多可以加括号,执行函数,传参数

from flask import Flask,render_template,Markup

app = Flask(__name__,template_folder='templates')
app.debug = True

@app.route('/')
def index():
    s1 = "<input type='text' value='姓名'/>"
    s2 = Markup("<input type='text' value='姓名'/>")
    a= 10
    return render_template('index.html',s1=s1,s2=s2,a=a)

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

请求响应

1.所有web:请求对象,响应对象(go,java,ptyhon)
  django:request(每个请求一个request),新手四件套
  flask:requset:全局的,但是也是每个请求一个request,新手三件套
    
2.flask在哪个里面执行代码,这个request代指的就是谁的request
3.flask请求对象,全局的request
	1.请求相关信息
	"""
        # 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))
	"""

    
4.flask的响应
	1.四件套:
    1.直接返回字符串
    2.返回模板:render_template
    3.返回重定向:redirect,
    4.返回json格式:jsonify
        
	2.响应中写cookie
    res = make_response('home') 
 		1.设置cookie
    	res.set_cookie('yyy', 'yyy', path='/home')
		2.删除cookie
      res.delete_cookie('key')
    3.响应头中写内容
      res = make_response('home')  # res 就是响应对象
      res.headers['xxx'] = 'xxx'

flask4.png

代码

请求相关信息


from flask import Flask,request

app = Flask(__name__)
app.debug = True

@app.route('/',methods = ['GET',"POST"])
def index():
    # 在哪个里面执行代码,这个request代指的就是谁的request
    print('不带域名,请求路径',request.path)  # /
    print('请求的方法',request.method)  # POST
    print('get请求提交的数据',request.args) # ImmutableMultiDict([('name-nana', '')])
    print('post请求提交的数据',request.form) # ImmutableMultiDict([('age', '13')])
    print('post和get提交的数据总和',request.values)  # CombinedMultiDict([ImmutableMultiDict([('name-nana', '')]), ImmutableMultiDict([('age', '13')])])
    print('客户端所带的cookie',request.cookies)  # ImmutableMultiDict([])
    print('请求头',request.headers) # Token: 123....
    print('不带域名,请求路径',request.path) # /
    print('不带域名,带参数的请求路径',request.full_path) # /?name-nana
    print('带域名带参数的请求路径',request.url)  # http://127.0.0.1:5000/?name-nana
    print('带域名请求路径',request.base_url)  # http://127.0.0.1:5000/
    print('域名',request.url_root) #  http://127.0.0.1:5000/
    print('域名',request.host_url) #  http://127.0.0.1:5000/
    print('服务端地址',request.host) # 127.0.0.1:5000
    print('文件',request.files) # ImmutableMultiDict([('myfile', <FileStorage: '开发模式.png' ('image/png')>)])
    # obj = request.files['the_file_name']
    # obj.save('/var/www/uploads/' + secure_filename(f.filename))

    return 'index'

@app.route('/home',methods = ['GET',"POST"])
def home():
    # 在哪个里面执行代码,这个request代指的就是谁的request
    print(request.path)  # /home

    return 'home'

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

上传文件

from flask import Flask,request

app = Flask(__name__)
app.debug = True

@app.route('/',methods = ['GET',"POST"])
def index():
    # 文件
    print(type(request.files.get('myfile')))  # <class 'werkzeug.datastructures.FileStorage'>
    # from werkzeug.datastructures import FileStorage
    res = request.files.get('myfile')
    res.save('xxx.png')

    return 'index'

@app.route('/home',methods = ['GET',"POST"])
def home():
    # 在哪个里面执行代码,这个request代指的就是谁的request
    print(request.path)  # /home
    return 'home'

if __name__ == '__main__':
    app.run()
@app.route('/', methods=['POST', 'GET'])
def index():
    print(type(request.files.get('myfiles')))
    with open('xx.zip', 'wb') as f:
        for line in request.files.get('myfiles'):
            f.write(line)

四件套


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

app = Flask(__name__)
app.debug = True

@app.route('/',methods = ['GET',"POST"])
def index():
    return 'index'

@app.route('/fun1',methods = ['GET',"POST"])
def fun1():
    return render_template('fun1.html')

@app.route('/fun2',methods = ['GET',"POST"])
def fun2():
    return redirect('http://www.baidu.com')


@app.route('/home',methods = ['GET',"POST"])
def home():
    return jsonify({'code': 100, 'msg': '成功', 'data': []})

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

响应头中写内容


from flask import Flask,request,render_template,redirect,jsonify,make_response

app = Flask(__name__)
app.debug = True


@app.route('/',methods = ['GET',"POST"])
def index():
    res = make_response('index') # res 就是响应对象
    res.headers['token']='fvsfvfs'
    return res

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

响应中写cookie


from flask import Flask,request,render_template,redirect,jsonify,make_response

app = Flask(__name__)
app.debug = True

@app.route('/',methods = ['GET',"POST"])
def index():
    res = make_response('index')  # res 就是响应对象
    res.set_cookie('username','nana',path='/')
    # res.delete_cookie('username')
    return res

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

session使用

1.flask中的session,没有在服务端存储数据的--->后期扩展,可也把session存到redis中
2.全局session
	放值:session['key']=value
  取值:session.get('key')
  删除值:session.pop('username', None)
    
3.session的运行机制
	1.django:
    1.生成一个随机字符串
    2.把数据保存到djagno-session表中
    3.把随机字符串返回给前端-->当cookie存到浏览器中了-->浏览器再发请求,携带cookie过来
    4.根据随机字符串去表中查--->转到request.session中
	2.flask
    1.把数据加密转成字符串: eyJuYW1lIjoibHF6In0.ZMnbJw.ZUceSaD0kGnU97tu9ZWm3380r00
    2.以cookie形式返回给前端--->保存到浏览器中
    3.浏览器再发请求,携带cookie过来
    4.加密符串--->解密--->放到session对象中

4.源码分析,看运行机制
	ps:入口app.session_interface
	1.flask默认使用:SecureCookieSessionInterface作为session的类
    1.请求来了,
        -客户端带了cookie--->取出cookie 中session对应的值
        -使用解密方式对它进行解密
        -放到session对象中
    2.请求走了
    	-把用户放到session中得数据
        -加密--->转成字符串-->以cookie形式返回给前端
        
  2.SecureCookieSessionInterface的方法e:
    open_session:请去来了用
    save_session:请求走了用   

代码

from flask import Flask,session

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

@app.route('/',methods = ['GET',"POST"])
def index():
    session['name']='cx'
    session['age']=14
    return 'ok'
  
@app.route('/home')
def home():
    print(session.get('name'))  # cx
    return 'home'

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