Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to understand the request context and application context objects in Flask

2025-03-29 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article will explain in detail how to understand the request context and application context objects in Flask. The content of the article is of high quality, so the editor shares it for you as a reference. I hope you will have some understanding of the relevant knowledge after reading this article.

When a request is processed in Flask, the application generates a request context object. The entire processing of the request will take place in this context object. This ensures that the processing of the request will not be disturbed. The specific code for processing the request is as follows:

Def wsgi_app (self, environ, start_response): with self.request_context (environ): # with statement generates a `response` object. Return response (environ, start_response)

Prior to Flask version 0.9, applications had only a "request context" object, which contained information related to request processing. At the same time, Flask is used to store the "request context" object according to a data structure LocalStack implemented in the werkzeug.local module. In version 0.9, Flask introduced the concept of "application context". The following two "context" objects are in the main Flask.

LocalStack

Before introducing "request context" and "application context", let's do a brief review of LocalStack. In the article local module, the Werkzeug library, we explained the three classes Local, LocalStack, and LocalProxy implemented in the werkzeug.local module. For their concepts and detailed descriptions, you can check out the above article. Here, we use an example to illustrate a data structure, LocalStack, used in Flask.

> from werkzeug.local import LocalStack > import threading # create a `LocalStack` object > local_stack = LocalStack () # View the information stored in local_stack > local_stack._local.__storage__ {} # define a function This function can add data to `LocalStack` > def worker (I): local_stack.push (I) # uses three threads to run the function `worker` > for i in range (3): t = threading.Thread (target=worker, args= (I) ) t.start () # View the information stored in local_stack again > local_stack._local.__storage__ {: {'stack': [2]},: {' stack': [1]},: {'stack': [0]}}

As you can see from the above example, the information stored in LocalStack is in the form of a dictionary: the key is the identification value of the thread / co-program, and the value is also in the form of a dictionary. Whenever an object is push into the LocalStack stack on a thread / co-program, it forms a "key-value" pair like the previous one. Such a structure implements thread / co-program isolation very well, and each thread / co-program determines the value stored in the stack structure according to its own thread / co-program identification value.

LocalStack also implements push, pop, top and other methods. Where the top method always points to the element at the top of the stack. The element at the top of the stack refers to the element in the current thread / co-program that is pushed into the stack, that is, local_stack._local.stack [- 1] (note that it is the element that is pushed into the object corresponding to the stack key).

Request context

All request processing in Flask takes place in the "request context", a concept that has been around since its inception. Due to the complexity of version 0.9 code, let's take version 0.1 code as an example. In essence, the working principle of these two versions of "request context" has not changed, but some features have been added in the new version, which will be explained later.

Request context-version 0.1

# Flask v0.1 class _ RequestContext (object): "The request context contains all request relevant information. It is created at the beginning of the request and pushed to the `_ request_ctx_ stack` and removed at the end of it. It will create the URL adapter and request object for the WSGI environment provided." Def _ _ init__ (self, app Environ): self.app = app self.url_adapter = app.url_map.bind_to_environ (environ) self.request = app.request_class (environ) self.session = app.open_session (self.request) self.g = _ RequestGlobals () self.flashes = None def _ enter__ (self): _ request_ctx_ Stack.push (self) def _ _ exit__ (self Exc_type, exc_value, tb): # do not pop the request stack if we are in debug mode and an # exception happened. This will allow the debugger to still # access the request object in the interactive shell. If tb is None or not self.app.debug: _ request_ctx_stack.pop ()

As can be seen from the above implementation of "request context":

The request context is a context object that implements the _ _ enter__ and _ _ exit__ methods. You can use the with statement to construct a context.

When you enter the context, a _ RequestContext object is pushed into the _ request_ctx_stack stack. This stack structure is the LocalStack stack mentioned above.

The _ RequestContext object pushed into the stack has some properties that contain all the relevant information about the request. For example, app, request, session, g, flashes. There is also a url_adapter, which can be used for URL matching.

Request processing can be done in the context of with statement construction. When exiting the context, the _ request_ctx_stack stack destroys the context object that was just stored.

The above running logic ensures that the request processing is always in the same context, which ensures that the request processing process will not be disturbed, and the request context object is saved in the LocalStack stack, and the thread / co-program isolation is well realized.

Here is a simple example:

# example-Flask v0.1 > > from flask import Flask, _ request_ctx_stack > import threading > > app = Flask (_ _ name__) # observe the information contained in _ request_ctx_stack first > _ request_ctx_stack._local.__storage__ {} # create a function Used to push the request context into the stack # in this example, do not use `with` statement > def worker (): # use the application's test_request_context () method to create the request context request_context = app.test_request_context () _ request_ctx_stack.push (request_context) # create three processes to execute the worker method > for i in range ( 3): t = threading.Thread (target=worker) t.start () # then observe the information contained in _ request_ctx_stack > _ request_ctx_stack._local.__storage__ {: {'stack': []} : {'stack': []},: {' stack': []}}

The above results show that a key-value pair is created for each thread in _ request_ctx_stack, and each key-value pair contains a request context object. If the with statement is used, the stored context object information is destroyed in the stack when leaving the context.

Request context-version 0.9

In version 0.9, Flask introduced the concept of "application context", which changed the implementation of "request context". This version of the request context is also a context object. After entering the context using the with statement, _ request_ctx_stack stores the context object. However, compared with version 0.1, there are several changes:

The request context implements push and pop methods, which makes the operation of the request context more flexible.

As the request context object is generated and stored in the stack structure, Flask generates an "application context" object, and the "application context" object is stored in another stack structure. This is the difference between the two versions.

Let's first take a look at the code related to version 0.9:

# Flask v0.9 def push (self): "" Binds the request context to the current context. "" Top = _ request_ctx_stack.top if top is not None and top.preserved: top.pop () # Before we push the request context we have to ensure that there # is an application context. App_ctx = _ app_ctx_stack.top if app_ctx is None or app_ctx.app! = self.app: app_ctx = self.app.app_context () app_ctx.push () self._implicit_app_ctx_stack.append (app_ctx) else: self._implicit_app_ctx_stack.append (None) _ request_ctx_stack .push (self) self.session = self.app.open_session (self.request) if self.session is None: self.session = self.app.make_null_session ()

We notice that in the pop method of "request context" in version 0.9, when you want to push a "request context" into the _ request_ctx_stack stack, you will first check whether there is an "application context" object at the top of the stack _ app_ctx_stack or whether the application of the "application context" object at the top of the stack is the current application. If it does not exist or is not the current object, Flask automatically turns it into an "application context" object and pushes it into _ app_ctx_stack.

Let's take a look at the relevant code when leaving the context:

# Flask v0.9 def pop (self, exc=None): "Pops the request context and unbinds it by doing that. This will also trigger the execution of functions registered by the: meth: `~ flask.Flask.teardown_ request` decorator... versionchanged:: 0.9 Added the `exc` argument." App_ctx = self._implicit_app_ctx_stack.pop () clear_request = False if not self._implicit_app_ctx_stack: self.preserved = False if exc is None: exc = sys.exc_info () [1] self.app.do_teardown_request (exc) clear_request = True rv = _ request_ctx_stack.pop () assert rv is self 'Popped wrong request context. (% r instead of r)'% (rv, self) # get rid of circular dependencies at the end of the request # so that we don't require the GC to be active. If clear_request: rv.request.environ ['werkzeug.request'] = None # Get rid of the app as well if necessary. If app_ctx is not None: app_ctx.pop (exc)

The details in the above code will not be discussed. Notice that when leaving the above "request context" environment, Flask will first destroy the "request context" object from the _ request_ctx_stack stack, and then decide to destroy the "application context" object according to the actual situation.

The following is illustrated by a simple example:

# example-Flask v0.9 > > from flask import Flask, _ request_ctx_stack _ app_ctx_stack > app = Flask (_ _ name__) # check the contents of the two stacks first > _ request_ctx_stack._local.__storage__ {} > > _ app_ctx_stack._local.__storage__ {} # generate a request context object > request_context = app.test_request_context () > request_context.push () # after the request context is pushed into the stack Check the contents of the two stacks again > _ request_ctx_stack._local.__storage__ {: {'stack': []}} > _ app_ctx_stack._local.__storage__ {: {' stack': []}} > request_context.pop () # when destroying the request context Check the contents of the two stacks again > > _ request_ctx_stack._local.__storage__ {} > _ app_ctx_stack._local.__storage__ {}

Application context

The relationship between "application context" and "request context" was briefly introduced in the previous section. So what is "application context"? Let's take a look at its classes first:

Class AppContext (object): "The application context binds an application object implicitly to the current thread or greenlet, similar to how the: class: `RequestContext` binds request information. The application context is also implicitly created if a request context is created but the application is not on top of the individual application context." Def _ init__ (self, app): self.app = app self.url_adapter = app.create_url_adapter (None) # Like request context, app contexts can be pushed multiple times # but there a basic "refcount" is enough to track them. Self._refcnt = 0 def push (self): "" Binds the app context to the current context. "" Self._refcnt + = 1 _ app_ctx_stack.push (self) def pop (self, exc=None): "Pops the app context. Self._refcnt-= 1 if self._refcnt > > from flask import Flask, _ request_ctx_stack _ app_ctx_stack # create two Flask applications > app = Flask (_ _ name__) > app2 = Flask (_ _ name__) # first check the contents of the two stacks > _ request_ctx_stack._local.__storage__ {} > _ app_ctx_stack._local.__storage__ {} # build an app request context Run app2 in this environment > with app.test_request_context (): print "Enter app's Request Context:" print _ request_ctx_stack._local.__storage__ print _ app_ctx_stack._local.__storage__ print with app2.app_context (): print "Enter app2's App Context:" Print _ request_ctx_stack._local.__storage__ print _ app_ctx_stack._local.__storage__ print # do something print "Exit app2's App Context:" print _ request_ctx_stack._local.__storage__ print _ app_ctx_stack._local.__storage__ Print # Result Enter app's Request Context: {: {'stack': []}} {: {' stack': []} Enter app2's App Context: {: {'stack': []}} {: {' stack': [ ]} Exit app2's App Context {: {'stack': []}} {: {' stack': []}}

In the above example:

We first created two Flask applications, app and app2

Then we build a request context for app. When entering this environment, look at the contents of the two stacks and find that the request context object and the application context object of the current request already exist in the two stacks. And the elements at the top of the stack are the request context and application context of app.

After that, we nest the application context of app2 in this environment. When you enter the application context of app2, the two contexts are isolated. If you look at the contents of the two stacks, you can find that the application context object of app2 is pushed into _ app_ctx_stack, and the top of the stack points to it. In the application context of app2, current_app will always point to app2.

When leaving app2's application context, the _ app_ctx_stack stack destroys the app2's application context object. At this point, we look at the contents of the two stacks and find that there are only the request context object and the application context object of the request of app in the two stacks.

Finally, after leaving app's request context, the two stacks destroy the request context object and application context object of app's request, and the stack is empty.

Global variables related to context objects

In Flask, in order to deal with some variables more conveniently, the concept of "global variable" is put forward. These global variables are:

# Flask v0.9 _ request_ctx_stack = LocalStack () _ app_ctx_stack = LocalStack () current_app = LocalProxy (_ find_app) request = LocalProxy (partial (_ lookup_object, 'request')) session = LocalProxy (partial (_ lookup_object,' session')) g = LocalProxy (partial (_ lookup_object) )) # Auxiliary function def _ lookup_object (name): top = _ request_ctx_stack.top if top is None: raise RuntimeError ('working outside of request context') return getattr (top, name) def _ find_app (): top = _ app_ctx_stack.top if top is None: raise RuntimeError (' working outside of application context') return top.app

As you can see, some of the "global variables" used in Flask, including current_app, request, session, g, and so on, come from context objects. Where current_app always points to the "application context" object at the top of the _ app_ctx_stack stack and is a reference to the current application. Request, session, g, and so on point to the "request context" object at the top of the _ request_ctx_stack stack, referring to the request, session, and g of the request context, respectively. However, since Flask 0. 10, object g is stored in the application context instead of the request context.

Another problem is that the LocalProxy class of the werkzeug.local module is used to form these "global variables". The main reason for using this class is to dynamically implement references to elements at the top of the stack. If you do not use this class, when generating the above "global variables", because they point to the top element of the stack, and the top element of the stack is now None, so these variables will also be set to None constants. Later, even if a context object is pushed into the stack, the corresponding "global variable" will not change. In order to dynamically reference the elements at the top of the stack, you must use the LocalProxy class of the werkzeug.local module.

This is how to understand the request context and application context objects in Flask. I hope the above content can be of some help and learn more knowledge. If you think the article is good, you can share it for more people to see.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 293

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report