• Flask之路由系统


    一、路由本质

    在flask中:

    from flask import Flask
    
    app = Flask(__name__)
    
    
    @app.route('/',methods=['GET','POST'],endpoint='index')
    def index():
        return 'index'
    
    
    if __name__ == '__main__':
        app.run()

    其中的视图函数被@app.route('/',methods=['GET','POST'],endpoint='index')装饰,在route函数中:

        def route(self, rule, **options):
            def decorator(f):
                endpoint = options.pop("endpoint", None)
                self.add_url_rule(rule, endpoint, f, **options)
                return f
            return decorator

    其中self就是app对象,那么执行顺序是:

    1、app.route('/',methods=['GET','POST'],endpoint='index')

    执行这一步主要就是通过闭包将route的参数传递到decorator的作用域中,执行route函数返回的就是decorator函数。

    2、@decorator

    当执行完第一步后,视图函数就会变成下面这样:

    @decorator
    def index():
        return 'index'

    此时index相当于被decorator修饰,在decorator函数中,endpoint如果存在就取出来,如果没有传递默认为None;然后值得注意的是:

    self.add_url_rule(rule, endpoint, f, **options)  #rule是‘/’,f是index函数,**options是methods参数

    这一步是将路由与视图加入到对应的映射关系中。

    3、add_url_rule

    用于添加路由与视图的对应关系,这也是flask中路由的本质,我们直接通过这个方法也是可以实现以上的功能:

    from flask import Flask
    
    app = Flask(__name__)
    
    
    def index():
        return 'index'
    
    app.add_url_rule('/', view_func=index, methods=['GET', 'POST'], endpoint='index')
    
    if __name__ == '__main__':
        app.run()

    4、add_url_rule参数详解

    add_url_rule中有很多参数,比如:

    rule #url规则
    view_func #视图名称
    defaults = None #缺省值为None,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数
    endpoint = None #缺省值为None,用于反向生成URL,即: url_for('名称')
    methods=None #缺省值为None,允许的请求方式,如:["GET","POST"]
    redirect_to=None #缺省值为None,重定向到指定地址
    strict_slashes=None #缺省值为None,对URL最后的 / 符号是否严格要求
    • defaults
    from flask import Flask
    
    
    app = Flask(__name__)
    
    @app.route('/',endpoint='index',defaults={'id':10})
    def index(id):
        print(id)  #接收传递的默认参数
        return 'index'
    
    if __name__ == '__main__':
        app.run()
    • redirect_to
    from flask import Flask
    
    app = Flask(__name__)
    
    
    @app.route('/index', methods=['GET', 'POST'], endpoint='index1', redirect_to="/index2")
    def index():
        return 'index'
    
    
    @app.route('/index2', methods=['GET', 'POST'], endpoint='index2')
    def index2():
        return 'index2'
    
    
    if __name__ == '__main__':
        app.run()
    • strict_slashes
    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route('/index',strict_slashes=False) #访问http://127.0.0.1:5000/index 或http://127.0.0.1:5000/index/  均可
    def index():
        return 'index'
    
    
    @app.route('/home',strict_slashes=True) #只能访问 http://127.0.0.1:5000/home
    def home():
        return 'home'
    
    if __name__ == '__main__':
        app.run()

    5、正则路由匹配

      在Flask中的路由是有一些变量规则的,通过把 URL 的一部分标记为<variable_name> 就可以在 URL 中添加变量。标记的 部分会作为关键字参数传递给函数。通过使用  <converter:variable_name>,可以 选择性的加上一个转换器,为变量指定规则。请看下面的例子:

    @app.route('/user/<username>')
    def show_user_profile(username):
        # show the user profile for that user
        return 'User %s' % escape(username)
    
    @app.route('/post/<int:post_id>')
    def show_post(post_id):
        # show the post with the given id, the id is an integer
        return 'Post %d' % post_id
    
    @app.route('/path/<path:subpath>')
    def show_subpath(subpath):
        # show the subpath after /path/
        return 'Subpath %s' % escape(subpath)

    转换器类型:

    string (缺省值) 接受任何不包含斜杠的文本
    int 接受正整数
    float 接受正浮点数
    path 类似 string ,但可以包含斜杠
    uuid 接受 UUID 字符串

    但是如果自己想指定规则,那么可以这样做:

    from flask import Flask, url_for
    from werkzeug.routing import BaseConverter
    import re
    
    app = Flask(__name__)
    
    
    # 1、自定义RegexConvert
    class RegecConvert(BaseConverter):
    
        def __init__(self, map, regex):
            super(RegecConvert, self).__init__(map)
            self.regex = regex
    
        def to_python(self, value):
            """进行路由匹配,匹配成功后返回给视图函数中的参数"""
            value = re.match(self.regex, value).group()
            return int(value)
    
        def to_url(self, value):
            """使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数"""
            val = super(RegecConvert, self).to_url(value)
            return val
    
    
    # 2、将RegecConvert加入到flask中
    app.url_map.converters['regex'] = RegecConvert  # 下次再使用该规则,就使用regex,这与int/float意思一样
    
    
    @app.route('/index/<regex("d+"):id>', endpoint='index')
    def index(id):
        print(id, type(id))  # 这个id是经过to_python方法匹配处理后的结果
        url_for('index', id=10)  # 这个id的值传递给to_url方法进行处理
        return 'index'
    
    
    if __name__ == '__main__':
        app.run()

    二、CBV

    from flask import Flask, views
    
    app = Flask(__name__)
    
    
    def auth(func):
        def inner(*args, **kwargs):
            result = func(*args, **kwargs)
            return result
    
        return inner
    
    
    class IndexView(views.MethodView):
        method = ['GET', ]
        decorators = [auth, ]
    
        def get(self):
            return 'get'
    
        def post(self):
            return 'post'
    
    
    app.add_url_rule('/', view_func=IndexView.as_view(name='index'))
    
    if __name__ == '__main__':
        app.run()

    启动web服务在5000端口,然后访问‘/’路径,就会执行IndexView.as_view(name='index'),显然会去继承的父类中寻找:

    class View(object):
        methods = None
        provide_automatic_options = None
        decorators = ()
    
        @classmethod
        def as_view(cls, name, *class_args, **class_kwargs):
    
            def view(*args, **kwargs):
                self = view.view_class(*class_args, **class_kwargs)
                return self.dispatch_request(*args, **kwargs)
    
            if cls.decorators:
                view.__name__ = name
                view.__module__ = cls.__module__
                for decorator in cls.decorators:
                    view = decorator(view)
    
            view.view_class = cls
            view.__name__ = name
            view.__doc__ = cls.__doc__
            view.__module__ = cls.__module__
            view.methods = cls.methods
            view.provide_automatic_options = cls.provide_automatic_options
            return view

    可以看到执行的顺序:as_view-->view-->dispatch_request,在dispatch_request进行反射和分发。

    class MethodView(with_metaclass(MethodViewType, View)):
      
        def dispatch_request(self, *args, **kwargs):
            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, "Unimplemented method %r" % request.method
            return meth(*args, **kwargs)

     至于IndexView中的decorators相当于装饰器,可以看到源码中进行循环所有的装饰器函数分别执行再赋值。

  • 相关阅读:
    Python3组合数据类型(元组、列表、集合、字典)语法
    tkinter模块常用参数(python3)
    python3的正则表达式(regex)
    QC的使用简介
    Linux常用命令
    Linux中jdk的安装和环境变量的配置
    大道至简阅读笔记07
    大道至简阅读笔记06
    大道至简阅读笔记05
    个人工作总结10
  • 原文地址:https://www.cnblogs.com/shenjianping/p/13216913.html
Copyright © 2020-2023  润新知