• flask/app.py-add_url_rule源码分析


    之前分析route方法的时候,可以看到中间会调用add_url_rule方法,add_url_rule方法和route方法一样属于Flask这个类的。

    add_url_rule方法主要用来连接url规则。具体工作方法和route类似。如果提供了视图函数,它将会和endpoint名字一起被注册

    #装饰器使用方法:
    @app.route('/')
    def index():
        pass
    
    # 等同与下面这种方法:
    def index():
        pass
    app.add_url_rule('/', 'index', index)
    
    If the view_func is not provided you will need to connect the endpoint
                   to a view function like so::
    # 如果视图函数没有被提供,需要用下面语法把视图函数和endpoint对应起来
     app.view_functions['index'] = index
      def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
            if endpoint is None:
                endpoint = _endpoint_from_view_func(view_func)
            options['endpoint'] = endpoint
            methods = options.pop('methods', None)
    
            # if the methods are not given and the view_func object knows its
            # methods we can use that instead.  If neither exists, we go with
            # a tuple of only ``GET`` as default.
            if methods is None:
                methods = getattr(view_func, 'methods', None) or ('GET',)
            if isinstance(methods, string_types):
                raise TypeError('Allowed methods have to be iterables of strings, '
                                'for example: @app.route(..., methods=["POST"])')
            methods = set(item.upper() for item in methods)
    
            # Methods that should always be added
            required_methods = set(getattr(view_func, 'required_methods', ()))
    
            # starting with Flask 0.8 the view_func object can disable and
            # force-enable the automatic options handling.
            provide_automatic_options = getattr(view_func,
                'provide_automatic_options', None)
    
            if provide_automatic_options is None:
                if 'OPTIONS' not in methods:
                    provide_automatic_options = True
                    required_methods.add('OPTIONS')
                else:
                    provide_automatic_options = False
    
            # Add the required methods now.
            methods |= required_methods
    
            rule = self.url_rule_class(rule, methods=methods, **options)
            rule.provide_automatic_options = provide_automatic_options
    
            self.url_map.add(rule)
            if view_func is not None:
                old_func = self.view_functions.get(endpoint)
                if old_func is not None and old_func != view_func:
                    raise AssertionError('View function mapping is overwriting an '
                                         'existing endpoint function: %s' % endpoint)
                self.view_functions[endpoint] = view_func
    源代码

    参数解析:

    • rule: 一个字符串格式的url规则,如:"/login". 注:就是从route方法中调用add_url_rule是传递的rule
    • endpoint: url规则的名字,用来反向生成url使用,默认是视图函数的名字。注:如果是route方法调用的,则这个参数是route方法传递过来的endpont
    • view_func: 视图函数,当对应的endpoint名字被请求时需要调用的函数。注:如果时router方法点用的add_url_rule,则这个参数时router方法传递过来的f
    • options: 类似与分析route时候的options.这个options是跟随:class:`~werkzeug.routing.Rule` object定义的,后面会分析这个对象中的具体参数,但有一个methods参数默认是只监听get方法。注:如果是router方法点用的add_url_rule,则这个参数时router方法传递过来的options函数

    函数体解析:

     1   def add_url_rule(self, rule, endpoint=None,  view_func=None, **options):
     2         if endpoint is None:
     3             # 如果没有提供endpoint参数,则默认用view_func的名字
     4             endpoint = _endpoint_from_view_func(view_func)
     5         # 把endpoint参数添加到options里面
     6         options['endpoint'] = endpoint
     7         # 从options中pop出methods参数,并把值赋给methods变量,如果没有则置为None
     8         methods = options.pop('methods', None)
     9         # moehods的值为None的情况下
    10         if methods is None:
    11             # 如果view_func函数中有这个methods参数,则使用view_func中的。如果没有则赋一个列表('GET',)给methods
    12             methods = getattr(view_func, 'methods', None) or ('GET',)
    13         # 如果methods是字符串类型
    14         if isinstance(methods, string_types):
    15             # 抛出一个异常:methods需要是一个可以迭代的字符串
    16             raise TypeError('Allowed methods have to be iterables of strings, '
    17                             'for example: @app.route(..., methods=["POST"])')
    18         # 把methods里面的item都改成大写
    19         methods = set(item.upper() for item in methods)
    20 
    21         # 在view_func里面定义了一个属性required_methods = ()
    22         # 作用:用来定义一些必须的方法,配合provide_automatic_options使用
    23         required_methods = set(getattr(view_func, 'required_methods', ()))
    24 
    25         # starting with Flask 0.8 the view_func object can disable and
    26         # force-enable the automatic options handling.
    27         # 在view_func里面定义了一个属性provide_automatic_options = None
    28         # 作用:用于禁用和强制启用一些自动选项
    29         provide_automatic_options = getattr(view_func,
    30             'provide_automatic_options', None)
    31 
    32         # 判断provide_automati_options是否为None
    33         if provide_automatic_options is None:
    34             # 如果OPTIONS字符串没有在methods里面
    35             if 'OPTIONS' not in methods:
    36                 # 则把provude_automatic_options改为True,并把OPTIONS添加到required_methods里面
    37                 provide_automatic_options = True
    38                 required_methods.add('OPTIONS')
    39             # 如果OPTIONS在methods里面,则把provide_automatic_options设置为False
    40             else:
    41                 provide_automatic_options = False
    42 
    43         # 合并required_methods和methods这两个集合到methods里面
    44         methods |= required_methods
    45         
    46         # 创建路由规则
    47         # 调用url_rule_class方法,由于在Flask类的全局变量中定义了:url_rule_class = Rule, Rule是werkzeug/routing.py里面的一个类
    48         # 也就是相当于实例化了Rule得到了rule对象,具体实例化后的结果请看Rule源码分析
    49         rule = self.url_rule_class(rule, methods=methods, **options)
    50         # 把provide_automatic_options属性添加到rule对象里面
    51         rule.provide_automatic_options = provide_automatic_options
    52 
    53         # 在Flask类的__init__里面定义了self.url_map = Map(),Map是werkzeug/routing.py里面的一个类
    54         # self.url_map相当与实例化了Map,.add则是调用了Map类里面的add方法
    55         # 具体运行结果,请参考Map源码分析,以及Map源码中的add方法分析
    56         self.url_map.add(rule)
    57         # 如果提供了view_func
    58         if view_func is not None:
    59             # 在flask类的__init__里面定义了self.view_functions = {},
    60             # 从字典里面取endpoint值并赋值为old_func,(endpoint是传递的参数,默认为视图函数名)
    61             old_func = self.view_functions.get(endpoint)
    62             # 如果old_func有值,并且不等于view_func
    63             if old_func is not None and old_func != view_func:
    64                 # 则抛出异常:视图函数映射被一个已经存在的函数名重写了
    65                 # 也就是说已经存在了一个endpoint:old_func的映射,但是old_fun却不是view_func,也就是说endpoint重复了
    66                 raise AssertionError('View function mapping is overwriting an '
    67                                      'existing endpoint function: %s' % endpoint)
    68             # 添加视图函数与endpoint映射到view_functions字典里面
    69             self.view_functions[endpoint] = view_func
  • 相关阅读:
    日常使用JAR包 MAVEN
    二维码
    常用验证
    文件操作
    邮件发送
    Spring获取bean对象帮助类
    mybatis-generator自动映射数据库,生成mapper.xml、mapperDao、entity
    JAVA爬虫
    MVC调试异常--未能将脚本调试器附加到计算机
    科研技能之文献管理Endnote X9——谈实用性
  • 原文地址:https://www.cnblogs.com/eric_yi/p/8325044.html
Copyright © 2020-2023  润新知