(5) In-depth analysis of Flask routing source code

  • The concept of routing (Route) is very important in all web frameworks. It is used to define the mapping relationship between URLs and corresponding processing functions (views). By defining routes, web framework applications can respond to different URL requests and execute corresponding logic.

Source code analysis:

When the Flask project (such as the hello world project below) is just started, Flask will definitely create a corresponding relationship between all routes and views.

from flask import Flask

app = Flask(__name__)


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


if __name__ == '__main__':
    app.run('localhost', 4000)

Analysis source code:

When the program runs @app.route('/index', methods=['GET', 'POST']), due to the existence of @ syntax sugar, the route function will be executed immediately, so enter the route function source code tracking:

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-akxZeP0V-1689295504389)(https://note.youdao.com/yws/res/18797/WEBRESOURCE72907d442753eb892b3902f227113780)]

The execution of the route function of the app object will return the decorator function, that is, @decorator is equivalent to @app.route('/index', methods=['GET', 'POST'])

The existence of @grammatical sugar will immediately execute @decorator

Namely decorator (index function)

[Because the index() function is not executed below the program, there is no need to continue to read the second step of @grammatical sugar ( details are explained in the article "(3) Flask Pre-Knowledge Stack - Decorator" )]

Continue to look at the source code of the route function, the decorator (index function) corresponds to —> the parameter f in the decorator is the index function.

insert image description here

self.add_url_rule(rule, endpoint, f, **options)

This sentence in the source code is the key, and its function is to add corresponding rules for routing and view functions.

Continue to track the source code and look at this function:

[Note that the function is in this object]add_url_rule()Flask(__name__)

insert image description here

The key point is the red box in the above picture.


A simple analysis of the source code of the above picture add_url_rule():

add_url_rule()Methods are ways to register URL rules in your Flask application.

def add_url_rule(
    self,
    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:
	"""
	*   rule:URL规则的字符串表示,对应'/index'。
	*   endpoint:可选参数,指定URL规则的名称(即终点)。
	*   view_func:可选参数,指定与URL规则关联的处理函数(视图函数)。
	*   provide_automatic_options:可选参数,控制是否自动提供OPTIONS方法。
	"""

First, the method processes and validates the parameters:

# 如果没有指定`endpoint`,则根据`view_func`自动生成一个。
if endpoint is None:
    endpoint = _endpoint_from_view_func(view_func)
options["endpoint"] = endpoint


# 从options参数中弹出`methods`字段,并根据不同情况设置默认值为"GET"。最后,将`methods`转换为大写,并确保它是一个集合。
methods = options.pop("methods", None)
if methods is None:
    methods = getattr(view_func, "methods", None) or ("GET",)
if isinstance(methods, str):
    raise TypeError("Allowed methods must be a list of strings, for example: @app.route(..., methods=['POST'])")
methods = {
    
    item.upper() for item in methods}

Next, according to view_functhe attributes and parameter values, set whether to automatically provide the OPTIONS method (we will briefly explain what this is at the end of the article):

# 如果没有指定`provide_automatic_options`,则从`view_func`的属性中获取。
if provide_automatic_options is None:
    provide_automatic_options = getattr(view_func, "provide_automatic_options", None)

# 如果仍然未指定,则根据methods是否包含"OPTIONS"来决定是否自动提供OPTIONS方法。
if provide_automatic_options is None:
    if "OPTIONS" not in methods:
        provide_automatic_options = True
        required_methods.add("OPTIONS")
    else:
        provide_automatic_options = False

Next, add the required methods to methodsthe collection and create an Ruleobject to represent URL rules:

# 将必需的方法合并到`methods`集合中(文末会讲这样的作用)
methods |= required_methods 

# 使用`url_rule_class`创建一个`Rule`对象来表示URL规则
rule = self.url_rule_class(rule, methods=methods, **options)
rule.provide_automatic_options = provide_automatic_options

# 将rule添加到应用程序的URL映射中。
self.url_map.add(rule)

Finally, if specified view_func, associate it with endpoint, and check for conflicts:

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(f"View function mapping is overwriting an existing endpoint function: {
      
      endpoint}")
    self.view_functions[endpoint] = view_func

If there is already a endpointprocessing function associated with it before, it will be raised AssertionError(familiar? The problem Flask raised in the decorator is the exception thrown here!!!).

Summary: add_url_rule()Method for adding URL rules to a Flask application. It parses and validates parameters, sets default values, and creates and registers Ruleobjects to represent URL rules. Then, associate a handler function with the URL rule and perform the necessary conflict checks.


Continue to press ① to track the source code:

insert image description here
insert image description here

My humble translation:

A Rule represents a URL pattern. A "Rule" has options that change how it behaves, and are passed to the "Rule" constructor.

Note that all arguments must be keyword arguments, except for rule strings, so as not to break the application when Werkzeug is upgraded.

To put it bluntly:

RuleClass to parse and store URL patterns. RuleA class represents a URL rule and contains information associated with it, such as URL pattern, HTTP method, handler function, etc.

Continue to press ② to track the source code:

Enter url_map:

insert image description here

Enter url_map_class:

insert image description here

My humble translation:

The map class stores all URL rules and some configuration parameters. Some config values ​​are only stored in 'Map' instances as they affect all rules, others are just default values

and can be overridden for each rule. Note that all parameters except ' rules ' as keyword arguments must be specified!

In short, in one sentence:

Mapis a URL mapper, which is used to store and manage all URL rules in the application.

Continue to track the add() function in the Map class (the comments are very clear~):

insert image description here

Continue to press ③ to track the source code (we will briefly talk about this line of source code at the end of the article):

insert image description here

The above is the source code of the three lines analyzed separately. It is just a simple analysis, and the follow-up will gradually deepen.

view_functions, Mapand Ruleput it together to see:

view_functionsThere is a close relationship between Map, and . RuleThey are important components in the Flask framework for handling URL routing.

  • view_functionsIt is an attribute of the Flask application object, which stores the mapping relationship between all routing endpoints (endpoint) and corresponding view functions (view function) in the application. It is a dictionary where the key is the endpoint name of the route and the value is the corresponding view function. app.view_functionsThis dictionary can be accessed and manipulated via .

  • Mapis a URL mapper that stores and manages all URL rules in your application. It is werkzeug.routing.Mapan instance of the class through which app.url_mapthe application's Mapobjects can be accessed. MapThe class provides methods for adding, finding and manipulating URL rules, including add(), match(), iter_rules()and so on.

  • RuleIt is the representation of URL rules, which defines a URL pattern, bound view functions, acceptable request methods and other information. RuleA class is werkzeug.routing.Rulean instance of a class, Mapused as part of an object. Each Ruleobject has a unique endpoint that identifies the rule. MapClasses use Ruleobjects to store and manage URL rules.

The relationship is as follows:

  • When defining a Flask application, we use @app.route()decorators to create URL rules and associate route endpoints with view functions. These URL rules will be stored in Mapthe object, by app.url_mapaccessing.
  • app.route()When the decorator is called , an Ruleobject is created inside the Flask framework to represent the URL rule. Objects are then Ruleadded to Mapobjects to form the entire URL mapping.
  • MapObjects use view_functionsproperties to find and call corresponding view functions. When a request arrives, Mapit will internally search for a matching Ruleobject based on the requested URL path and HTTP method, and obtain the bound view function from it.
  • Through the combination of view_functionsdictionaries and Mapobjects, Flask can realize the functions of automatic routing and request processing. It uses the endpoint of the URL as a view_functionskey to find the corresponding view function; at the same time, according to the requested URL and method, Mapfinds the matching Ruleobject and extracts the view function to call it.

It can be seen that , view_functions, Mapand Ruleare the key components for processing URL routing in the Flask framework. They cooperate with each other to achieve flexible routing management and request processing mechanisms.

To sum up—two ways to add routes:

from flask import Flask

app = Flask(__name__)
app.config.from_object()


# 方式一    (就用这个!)
@app.route('/index', methods=['GET', 'POST'])
def index():
    return 'index'


def order():
    return 'order'


# 方式二
app.add_url_rule('/order', view_func=order)

if __name__ == '__main__':
    app.run('localhost', 4000)

expand:

(1) In-depth provide_automatic_optionsparameters

provide_automatic_optionsparameter is used to control whether the OPTIONS method is automatically provided.

In the HTTP protocol, the OPTIONS method is used to obtain the request methods supported by the specified URL. The Flask framework automatically handles OPTIONS requests by default and returns a response containing the allowed request methods.

When provide_automatic_optionsthe parameter is True, it means that the application will automatically provide support for the OPTIONS method. If the requested URL matches a routing rule, but does not explicitly define a handler for the OPTIONS method, Flask will automatically generate a handler for the OPTIONS method to respond to the request.

When provide_automatic_optionsthe parameter is False, it means that the application will not automatically provide support for the OPTIONS method. Even if the requested URL matches a routing rule, but does not explicitly define a handler for the OPTIONS method, Flask will not automatically generate a handler for the OPTIONS method. This means that if the client sends an OPTIONS request, and there is no corresponding handler function to handle the request, Flask will return a 405 Method Not Allowed response.

By setting provide_automatic_optionsparameters, developers can flexibly control whether the application automatically provides support for the OPTIONS method to meet specific needs.

(2) methods |= required_methodsFunction

methods |= required_methodsis the operation used during route definition in Flask to merge required methods into the set of acceptable methods.

In Flask, the allowed request methods can be specified by passing the request method as a decorator parameter to the routing function. For example:

@app.route('/', methods=['GET', 'POST'])
def index():
    # 处理GET和POST请求
    pass

In the above example, the routing function index()is defined to only accept GET and POST requests. But sometimes, you may also need to deal with other methods, such as OPTIONS or PUT, etc. That's required_methodswhat it does.

required_methodsis a collection containing methods that should always be added to the set of acceptable methods. These methods are usually application-specific and must be supported.

|=Merge required_methodsthe sets into sets by using the bitwise OR (OR) operator methods, and assign the result to methods. This ensures that methodsall required methods are included in the collection.

For example, if methodsthe collection already contained ['GET'] and required_methodsthe collection contained ['OPTIONS'], then methods |= required_methodsafter execution, methodsthe collection would become ['GET', 'OPTIONS'].

The purpose of this is to ensure that the route can handle all required request methods, thus providing more comprehensive HTTP method support.

(3) In-depthself.view_functions

self.view_functionsIs a dictionary used to store the mapping relationship between all routing endpoints (endpoints) and corresponding view functions (view functions) in the Flask application.

It is created during initialization of the Flask application object and exists as an instance property. self.view_functionsThe definition of the dictionary is as follows:

self.view_functions: Dict[str, Callable] = {
    
    }

This is meant self.view_functionsto be a dictionary of key-value pairs, where the key is the endpoint name of the route and the value is the corresponding view function. Specifically, keys are strings and values ​​are callables, usually Python functions.

When @app.route()defining routes with decorators, the Flask framework automatically adds route endpoints and corresponding view functions to self.view_functionsthe dictionary. In this way, when receiving a request, Flask can find the corresponding view function from the dictionary according to the routing end point, and execute the corresponding logic.

Practical combat - how to use self.view_functionsdictionaries:

from flask import Flask

app = Flask(__name__)


@app.route('/')
def demo():
    return 'Hello, World!'


@app.route('/index')
def index():
    return 'index'


if __name__ == '__main__':
    print(app.view_functions)

Running it will output app.view_functionsthe contents of the dictionary:

{
    
    
	'static': <function Flask.__init__.<locals>.<lambda> at 0x000001A3334258B0>, 
	'demo': <function demo at 0x000001A3334364C0>, 
	'index': <function index at 0x000001A333436550>
}

app.view_functionsYou can view and operate the view functions registered in the Flask application through access , such as obtaining all endpoint names, obtaining the corresponding view functions, and so on.

Guess you like

Origin blog.csdn.net/qq_44907926/article/details/131715599