Flask篇:flask路由系统、flask模板语法、flask请求响应

一、路由系统

1.路由使用

flask 路由写法:

基于装饰器

from flask import Flask

app = Flask(__name__)

@app.route('/index', methods=['GET'], endpoint='index') # 第一个参数为url路径,第二个参数为请求方式,第三个为路由名称
def index():
    return 'hello'

另一种写法(与django类似)

from flask import Flask

app = Flask(__name__)

@app.route('/index', methods=['GET'], endpoint='index') # 第一个参数为url路径,第二个参数为请求方式,第三个为路由名称
def index():
    return 'hello'
    
app.add_url_rule('/index', view_func=index,)

2.转换器

转换器不设置类型时默认为default

转换器类型 获取到的值类型
default UnicodeConverter(传入什么类型数据就是什么类型)
string UnicodeConverter(传入什么类型数据就是什么类型)
any AnyConverter(任意类型)
path PathConverter (可以识别/的url类型)
int IntegerConverter(整数类型)
float FloatConverter(浮点数类型)
uuid UUIDConverter(uuid类型)

例如:

@app.route('/index/<pk>', methods=['GET'], endpoint='index') #默认类型转化器
def index(pk):
    return 'hello'

@app.route('/index/<int:pk>', methods=['GET'], endpoint='index') #指定类型转换器
def index(pk):
    return 'hello'

3.路由本质

从@app.route寻找源码,route会运行add_url_rule

@setupmethod
def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]:
   def decorator(f: T_route) -> T_route:
       endpoint = options.pop("endpoint", None)
       self.add_url_rule(rule, endpoint, f, **options)  # 此处是重点
       return f

   return decorator
@setupmethod
def add_url_rule(
    self,  # 此处的self是app
    rule: str,
    endpoint: t.Optional[str] = None,
    view_func: t.Optional[ft.RouteCallable] = None,
    provide_automatic_options: t.Optional[bool] = None,
    **options: t.Any,
) -> None:
	def decorator(f: F) -> F:
		self.view_functions[endpoint] = f
		return f

return decorator

而app对象自身是没有add_url_rule方法的
运行时寻找add_url_rule方法是Flask类的

结合以上的代码分析
我们只需要自己实现add_url_rule方法即可完成路由的配置

# 示例
app.add_url_rule('/order/<string:pk>',view_func=order)
app.add_url_rule('/index',view_func=index)

4.基于类的视图cbv

4.1 cbv写法

# cbv写法,继承MethodView,跟djagno很像
from flask.views import MethodView

class Home(MethodView):
    methods=['POST']
    # decorators = (装饰器名字,装饰器名字2,)
    def get(self):
        return 'home'

    def post(self):
        return 'home-post'

app.add_url_rule('/home', view_func=Home.as_view(name='home'))

4.2 cbv源码分析

(1) as_view的name是别名,fbv的endpoint是别名,现在写cbv,name它最终也是endpoint,而且必须写,即便写了endpoint
(2) Home.as_view是view函数的内存地址,请求来了执行MethodView中的:  
        self.dispatch_request(),  # 重写了dispatch_request-->根据请求方式执行视图类中跟请求方式同名的方法,因此如果视图类继承了View,需要重写dispatch_request
(3) dispatch_request源码:  # 最新版本跟老版本有所不同,逻辑基本上一样,通过请求方式不同进行反射,然后执行类的对应方法
         def dispatch_request(self, **kwargs: t.Any) -> ft.ResponseReturnValue:
            meth = getattr(self, request.method.lower(), None)

            # If the request method is HEAD and we don't have a handler for it
            # retry with 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)
(4) fbv和cbv别名
    app.add_url_rule('/index', view_func=index)  # 路由有个别名,如果不写endpoint,会以函数名作为endpoint
    app.add_url_rule('/home', view_func=Home.as_view(name='home'))  # name就是路径的别名,endpoint

4.3 cbv添加装饰器和请求方式

class Home(MethodView):
    methods=['POST']
    decorators = (装饰器名字,装饰器名字2,)  # 最左边的在最下面
    def get(self):
        return 'home'

    def post(self):
        return 'home-post'
(1) cbv加装饰器, 在类中写 decorators = (装饰器名字,装饰器名字2,),第一个位置的会放在最下层,多个装饰器执行顺序是从【上往下执行】
(2) cbv只允许某个请求方式   methods=['POST']

5.add_url_rule参数

5.1 参数

    -rule:请求的路径,可以使用转换器
    -endpoint:别名--》反向解析
    -view_func:视图类.as_view(name='xx')(视图函数内存地址)
    -methods:允许的请求方式
    # ---------以下不重要-----
    -defaults:字典,给视图函数传默认值
    -strict_slashes:对URL最后的 / 符号是否严格要求
    -redirect_to

5.2 @app.route源码分析 ---> add_url_rule

# 装饰器   @route  python特殊语法糖,会把下面的函数当参数传入  order=route(order)  以后调用order本质就是在执行route(order)()
# route的内层函数---->本质是self.add_url_rule(rule, endpoint, f, **options)

@setupmethod
def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]:
    def decorator(f: T_route) -> T_route:
        endpoint = options.pop("endpoint", None)
        self.add_url_rule(rule, endpoint, f, **options)  # self是app对象,add_url_rule 其实就是Flask类的add_url_rule方法

        return f
    return decorator

# 所以我们可以不使用装饰器来注册路由,而自己写add_url_rule来注册路由,这就跟django比较相似了
app.add_url_rule('/order/<string:pk>',view_func=order)
app.add_url_rule('/index',view_func=index)

二、模板

2.1 模板语法

# 模板语法: 
    -django 是自己的模板语法,dtl
    -flask使用第三方,兼容dtl,但是它可以加括号,可以使用[],处理了xss攻击
    -xss,csrf,cors分别是什么?
    -django,flask处理了xss攻击,不存在这个攻击,原理是什么?
    -使用了html的特殊字符替换,但是如果使用了 |safe 或者Markup ,就不会渲染到页面上
        from  flask import Flask,render_template,Markup
            app=Flask(__name__)

            @app.route('/')
            def index():
           #----------------------------------------------------------
                a='<a href="http://www.baidu.com">点我看美女</a>'
                a=Markup(a)
           #----------------------------------------------------------
                return render_template('home.html',name='lz',age=19,url=a,add=add)
            if __name__ == '__main__':
                app.run()

三、Flask请求响应(请求对象属性方法;响应四件套、响应设置cookie、添加响应头)

from flask import Flask, request,make_response,render_template

app = Flask(__name__)
app.debug=True


@app.route('/login.html', methods=['GET', "POST"])
def login():
    ####请求对象的属性和方法####
    # request:是全局的request,用起来就当是每个请求都有一个request即可
    print(request.method) # 请求方式
    print(request.args) # get 请求提及的数据
    print(request.form) # post提交的数据
    print(request.values)  # get,post提交的数据总和
    print(request.cookies)  # cookies
    print(request.headers)  # 请求头
    print(request.path)  # 不带域名,请求路径
    print(request.full_path)  # 全路径,不带域名,带参数的请求路径
    print('-----',request.script_root)
    print(request.url)      # 带域名带参数的请求路径
    print(request.base_url)  # 带域名请求路径
    print(request.url_root)   # 域名
    print(request.host_url)  # 域名+端口
    print(request.host)    # 不带http的域名+端口

    from werkzeug.datastructures import FileStorage
    print(type(request.files.get('files')))
    # obj = request.files['files']
    # obj.save('/var/www/uploads/' + secure_filename(f.filename))


    ### 响应对象四件套,设置cookie和响应头
    ## 1 响应四件套
        # return "字符串"
        # return render_template('html模板路径',**{})
        # return redirect('/index.html')
        # return jsonify({'k1':'v1'})
    
    ## 2 向浏览器中写入cookie,四件套都可以使用make_response包裹一下变成响应对象
        res=make_response(render_template('home.html'))
        res.set_cookie('name','lqz')
        # delete_cookie 删除cookie

    ## 3 向浏览器中写响应头
        # res.headers['X-Something'] = 'A value'


    return res


if __name__ == '__main__':
    app.run()
posted @ 2022-08-08 17:47  马氵寿  阅读(175)  评论(0编辑  收藏  举报