zoukankan      html  css  js  c++  java
  • flask之路由详解

    一、路由的本质

    flask的路由直接在函数上使用装饰器的话非常的乱,那可不可以想django一样把路由都写到一起呢。

    查看源码,我们知道原来的路由就是一个装饰器,装饰器的第一个参数就是路由规则

    实际上在装饰器内的闭包函数最终调用的是def add_url_rule(self,rule,endpoint=None,view_func=None,provide_automatic_options=None,**options):

    '''
    rule:路由规则
    endpoint:反向解析别名,和CBV中as_view(name=...)的name是一样的。因为在源码内部,实际上也会去取参数view_func的__name__也就是指定的函数或类的名字
    view_func:响应对象
    '''
    

    因此我们可以直接改写路由。

    将原来装饰器修饰的路由,改写为使用add_url_rule的路由

    from  flask import Flask
    app = Flask(__name__)
    
    @app.route("/")
    def index():
        return "ok"
    
    if __name__ == '__main__':
        app.run()
    

    改写为

    from  flask import Flask
    app = Flask(__name__)
    
    @app.route("/")
    def index():
        return "ok"
    
    # 路由匹配规则和响应函数
    app.add_url_rule("/index", view_func=index)
    
    if __name__ == '__main__':
        app.run()
    

    二、CBV

    和django一样,flask也是有CBV的,都是通过as_view()来返回view对象,通过匹配然后执行view函数完成dispatch_request的响应方式的分发。

    不同的是。as_view()中必须传递一个name,这个name就是作为反向解析的名字给类的__name__

    flask导入的views.View类必须实现dispatch_request方法,不然匹配路由成功后执行view函数完成分发会报错。因为源码中必须让你实现

    from flask import Flask,views
    app = Flask(__name__)
    
    
    #简单模式
    class IndexView(views.View):
        def dispatch_request(self):
            print('Index')
            return 'Index!'
        
    app.add_url_rule('/index1', view_func=IndexView.as_view(name='index1'))	# name=endpoint 反向解析的别名
    
    if __name__ == '__main__':
        app.run()
    

    2.1 使用views.MethodView类

    这个类已经帮我们实现好了dispatch_request方法,就不需要自己再去写了。而他帮你实现的dispatch_request方法中做的事和Django中的dispath方法中做的事情是一致的。都是通过反射去取响应的请求方式名同名的函数

    from flask import Flask,views
    app = Flask(__name__)
    
    #通常用此方式
    class IndexView(views.MethodView):
            def get(self):
                return 'Index.GET'
    
            def post(self):
                return 'Index.POST'
            
    app.add_url_rule('/index', view_func=IndexView.as_view(name='index'))  # name=endpoint
    
    
    if __name__ == '__main__':
        app.run()
    

    2.2 指定响应的请求方式类型

    无论是FBV还是CBV的实现方式都可以在函数内部或类内部添加methods = ['GET',"POST"].当app.add_url_rule执行时会通过反射去函数或类内部的methods中取指定的响应方法,如果没有写,默认只响应get方式请求。

    但如果是CBV的方式,没有写methods则和django一样去取类内部实现的方法。但如果写了methods,只会响应methods中的请求方式对应的方法

    '''CBV'''
    
    from flask import Flask,views
    app = Flask(__name__)
    
    class IndexView(views.MethodView):
            methods = ['GET']	# 只响应GET请求对于的get方法
    
            def get(self):
                return 'Index.GET'
    
            def post(self):
                return 'Index.POST'
            
    app.add_url_rule('/index', view_func=IndexView.as_view(name='index'))
    
    if __name__ == '__main__':
        app.run()
    

    2.3 指定装饰器修饰

    在使用CBV,添加对应的路由是需要通过as_view来得到view对象。而在as_view()内部,会根据类属性decorators=[auth, ] 来执行[]中对应的装饰器。也就是说,当程序执行时,进入as_view()后,会给该装饰器传入一个view对象,然后进入对应的装饰器,该装饰器必须返回一个view对象,否则就会报错。

    传进去一个view,返回一个同名的view对象,这不就是装饰器嘛。给view加了一层装饰器,无论哪个路由匹配成功,都会先进入该装饰器。

    from flask import Flask,views,url_for,jsonify,render_template
    app = Flask(__name__)
    
    def auth(view):
        def inner(*args,**kwargs):
            if view.__name__=="index":
                res = view(*args,**kwargs)
            else:
                # res = render_template("404.html")
                res = jsonify({"status": 0,"msg":"傻逼"})
            return res
        return inner
    
    
    #通常用此方式
    class IndexView(views.MethodView):
            # 给dispatch_request加装饰器
            decorators = [auth, ]
    
            def get(self):
                return 'Index.GET'
    
            def post(self):
                return 'Index.POST'
    app.add_url_rule('/index', view_func=IndexView.as_view(name='index1'))
    
    if __name__ == '__main__':
        app.run()
    

    三、路由参数

    @app.routeapp.add_url_rule参数:

    '''
    rule:路由规则
    
    endpoint:反向解析别名,和CBV中as_view(name=...)的name是一样的。因为在源码内部,实际上也会去取参数view_func的__name__也就是指定的函数或类的名字
    
    view_func:响应对象
    
    defaults:默认值为None, 当URL中无参数,函数需要参数时,使用defaults = {'k': 'v'}
    
    methods:允许的请求方式,如:["GET", "POST"]
    
    
    strict_slashes: 对URL最后的 / 符号是否严格要求,默认等于None
    
    
    redirect_to: 重定向到指定地址
    '''
    
    • url_for: 可以根据反向解析的别名来拿到对应路由
    from  flask import Flask,views,url_for
    app = Flask(__name__)
    
    @app.route("/index/",endpoint="a",methods=["POST","GET"],strict_slashes=None,redirect_to="/index2")
    def index():
        return "ok"
    
    @app.route("/index2")
    def index2():
        # 打印反向解析的别名是a的路由
        print(url_for("a"))
        return "吃饭去了"
    
    
    
    if __name__ == '__main__':
        app.run()
    

    四、路由转换器

    路由转化器,其实就是django中路由的有名分组,通过参数名来得到路由的参数。区别是不用正则,但是可以指定参数类型。

    from  flask import Flask
    app = Flask(__name__)
    
    # 和有名分组一样,只不过不用正则了
    @app.route("/<string:flag>")
    def index(flag):
        return f"jason is sb ? {flag}"
    
    
    if __name__ == '__main__':
        app.run()
    

    默认路由转化器参数类型

    DEFAULT_CONVERTERS = {
        'default':          UnicodeConverter,
        'string':           UnicodeConverter,
        'any':              AnyConverter,
        'path':             PathConverter,
        'int':              IntegerConverter,
        'float':            FloatConverter,
        'uuid':             UUIDConverter,
    }
    

    4.1 自定义转换器

    • 1 写类,继承BaseConverter,实现三个方法init、to_python、to_url
    • 2 注册:app.url_map.converters['regex'] = RegexConverter
    • 3 使用:@app.route('/index/<regex("d+"):nid>') 正则表达式会当作第二个参数传递到类中
    #1 写类,继承BaseConverter,实现三个方法init、to_python、to_url
    #2 注册:app.url_map.converters['regex'] = RegexConverter
    #3 使用:@app.route('/index/<regex("d+"):nid>')  正则表达式会当作第二个参数传递到类中
    from flask import Flask, views, url_for
    from werkzeug.routing import BaseConverter
    
    app = Flask(import_name=__name__)
    
    class RegexConverter(BaseConverter):
        """
        自定义URL匹配正则表达式
        """
        def __init__(self, map, regex):
            super(RegexConverter, self).__init__(map)
            self.regex = regex
    
        def to_python(self, value):
            """
            路由匹配时,匹配成功后传递给视图函数中参数的值
            """
            return int(value)+123
    
        def to_url(self, value):
            """
            使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
            """
            # 先执行父类方法
            val = super(RegexConverter, self).to_url(value)
            return val+"json"
    
    # 添加到flask中
    app.url_map.converters['regex'] = RegexConverter
    @app.route('/index/<regex("d+"):nid>')
    def index(nid):
        print(nid)
        print(url_for('index', nid='888'))  # 使用反向解析,会执行自定义转换器的to_url
        return 'Index'
    
    if __name__ == '__main__':
        app.run()
    
  • 相关阅读:
    golang与vscode的安装与配置
    numpy学习之前的必要数学知识:线性代数
    分布式系统设计系列 -- 基本原理及高可用策略
    微服务的4个设计原则和19个解决方案
    JAVA8 十大新特性详解
    ConcurrentHashMap总结
    Java NIO理解与使用
    深入了解 Java-Netty高性能高并发理解
    java内存泄漏的定位与分析
    Netty高性能编程备忘录(下)
  • 原文地址:https://www.cnblogs.com/XuChengNotes/p/12149300.html
Copyright © 2011-2022 走看看