플라스크의 컨텍스트 스택의 목적은 무엇입니까?
저는 한동안 요청/응용 프로그램이 어떻게 작동하는지 또는 왜 원래대로 설계되었는지 완전히 이해하지 못한 채 요청/응용 프로그램 컨텍스트를 사용해 왔습니다.요청 또는 애플리케이션 컨텍스트와 관련하여 "스택"의 목적은 무엇입니까?이 두 개의 스택은 별개입니까, 아니면 둘 다 하나의 스택에 속합니까?요청 컨텍스트가 스택에 푸시됩니까? 아니면 스택 자체입니까?여러 컨텍스트를 서로 밀어넣거나 팝업할 수 있습니까?만약 그렇다면, 제가 왜 그렇게 하고 싶어할까요?
모든 질문에 대해 죄송합니다만, 요청 컨텍스트 및 응용 프로그램 컨텍스트에 대한 설명서를 읽고 난 후에도 여전히 혼란스럽습니다.
여러 앱
플라스크가 여러 개의 앱을 가질 수 있다는 것을 깨닫기 전까지는 애플리케이션 컨텍스트(및 그 목적)가 실제로 혼란스럽습니다.단일 WSGI Python 인터프리터가 여러 플라스크 응용 프로그램을 실행하도록 원하는 상황을 상상해 보십시오.우리는 청사진을 말하는 것이 아니라 완전히 다른 플라스크 응용 프로그램을 말하는 것입니다.
응용프로그램 발송 예제의 플라스크 문서 섹션과 유사하게 설정할 수 있습니다.
from werkzeug.wsgi import DispatcherMiddleware
from frontend_app import application as frontend
from backend_app import application as backend
application = DispatcherMiddleware(frontend, {
'/backend': backend
})
완전히 다른 두 개의 플라스크 응용프로그램이 "프론트엔드"와 "백엔드"로 작성되고 있습니다. 다른말하면로,면하▁in,Flask(...)
응용 프로그램 생성자가 두 번 호출되어 플라스크 응용 프로그램의 두 인스턴스를 만들었습니다.
콘텍스트
플라스크를 사용할 때는 글로벌 변수를 사용하여 다양한 기능에 액세스하는 경우가 많습니다.예를 들어, 당신은 아마도 다음과 같은 코드를 가지고 있을 것입니다.
from flask import request
그러면 보기 중에 다음을 사용할 수 있습니다.request
현재 요청의 정보에 액세스합니다. 물론. 뻔지하.request
는 일반적인 전역 변수가 아닙니다. 실제로는 컨텍스트 로컬 값입니다.다시 말해서, 무대 뒤에는 "내가 전화를 걸 때"라고 말하는 어떤 마법이 있습니다.request.path
를 path
의 request
현재 요청의 개체입니다."두 개의 서로 다른 요청은 다음에 대해 서로 다른 결과를 가집니다.request.path
.
실제로 여러 스레드로 Flask를 실행하더라도 Flask는 요청 개체를 격리할 수 있을 정도로 똑똑합니다.그렇게 함으로써, 각각 다른 요청을 처리하는 두 개의 스레드가 동시에 호출하는 것이 가능해집니다.request.path
각 요청에 대한 정확한 정보를 얻을 수 있습니다.
조립하기
그래서 우리는 플라스크가 동일한 인터프리터에서 여러 응용 프로그램을 처리할 수 있고 또한 플라스크가 "콘텍스트 로컬" 글로벌을 사용할 수 있는 방법 때문에 "현재" 요청이 무엇인지 결정하는 메커니즘이 있어야 한다는 것을 이미 보았습니다.request.path
).
이러한 아이디어를 종합하면 플라스크는 "현재" 응용 프로그램이 무엇인지 결정할 수 있는 방법이 있어야 한다는 것도 의미가 있습니다!
다음과 유사한 코드도 있을 수 있습니다.
from flask import url_for
우처럼처럼.request
를 들어, 들를어, url_for
함수에는 현재 환경에 종속된 논리가 있습니다.그러나 이 경우 어떤 앱이 "현재" 앱으로 간주되는지에 따라 논리가 크게 좌우된다는 것은 분명합니다.에서 "및 "앱"/를 가질 수 "/login" " "/login"은 "/" 경로입니다.url_for('/login')
보기가 프런트엔드 또는 백엔드 앱에 대한 요청을 처리하는지 여부에 따라 다른 값을 반환해야 합니다.
질문에 답하려면...
요청 또는 애플리케이션 컨텍스트와 관련하여 "스택"의 목적은 무엇입니까?
요청 컨텍스트 문서에서:
요청 컨텍스트는 내부적으로 스택으로 유지되므로 여러 번 푸시 및 팝업할 수 있습니다.이것은 내부 리디렉션과 같은 것들을 구현하는 데 매우 유용합니다.
즉, 일반적으로 이러한 "현재" 요청 또는 "현재" 응용프로그램 스택에 0개 또는 1개의 항목이 있더라도 더 많은 항목이 있을 수 있습니다.
주어진 예는 요청이 "내부 리디렉션"의 결과를 반환하도록 하는 경우입니다.사용자가 A를 요청하지만 사용자 B로 돌아가고 싶다고 가정합니다.대부분의 경우 사용자에게 리디렉션을 실행하고 사용자에게 리소스 B를 가리킵니다. 즉, 사용자가 두 번째 요청을 실행하여 B를 가져옵니다.이것을 처리하는 약간 다른 방법은 내부 리디렉션을 수행하는 것입니다. 즉, A를 처리하는 동안 플라스크는 리소스 B에 대해 자신에게 새 요청을 하고 이 두 번째 요청의 결과를 사용자의 원래 요청의 결과로 사용합니다.
이 두 개의 스택은 별개입니까, 아니면 둘 다 하나의 스택에 속합니까?
그것들은 두 개의 별도 스택입니다.그러나 이것은 구현 세부사항입니다.더 중요한 것은 스택이 있다는 것이 아니라 언제든지 "현재" 애플리케이션 또는 요청(스택의 맨 위)을 받을 수 있다는 사실입니다.
요청 컨텍스트가 스택에 푸시됩니까? 아니면 스택 자체입니까?
"요청 컨텍스트"는 "요청 컨텍스트 스택"의 한 항목입니다."앱 컨텍스트" 및 "앱 컨텍스트 스택"에서도 마찬가지입니다.
여러 컨텍스트를 서로 밀어넣거나 팝업할 수 있습니까?만약 그렇다면, 제가 왜 그렇게 하고 싶어할까요?
플라스크 응용 프로그램에서는 일반적으로 이 작업을 수행하지 않습니다.원하는 위치의 한 예로 내부 리디렉션이 있습니다(위에서 설명).그러나 이 경우에도 플라스크가 새로운 요청을 처리하게 되므로 모든 푸시/팝핑이 플라스크에서 대신 처리됩니다.
그러나 스택을 직접 조작하려는 경우도 있습니다.
요청 외부에서 코드 실행 중
사람들이 가지고 있는 한 가지 일반적인 문제는 아래와 같은 코드를 사용하여 SQL 데이터베이스와 모델 정의를 설정하기 위해 Flask-SQL 화학 확장을 사용한다는 것입니다.
app = Flask(__name__)
db = SQLAlchemy() # Initialize the Flask-SQLAlchemy extension object
db.init_app(app)
그런 다음 그들은 사용합니다.app
그리고.db
셸에서 실행해야 하는 스크립트의 값입니다.예를 들어 "setup_tables.py" 스크립트는 다음과 같습니다.
from myapp import app, db
# Set up models
db.create_all()
플라스크-SQ 경우플-SQ는LA 화학 은 LA 화학다대알에 대해 있습니다.app
프로그램, 용응프램그 동안, 그나실행중러.create_all()
응용프로그램 컨텍스트가 없다고 불평하는 오류가 발생합니다.됩니다. 당신은 할 때 해야 하는지 않았습니다. 당신은 플라스크를 실행할 때 어떤 애플리케이션을 다루어야 하는지 결코 말하지 않았습니다.create_all
방법.
당신은 왜 당신이 이것이 필요하지 않은지 궁금할 것입니다.with app.app_context()
보기에서 유사한 기능을 실행할 때 호출합니다.그 이유는 플라스크가 실제 웹 요청을 처리할 때 이미 응용프로그램 컨텍스트의 관리를 처리하기 때문입니다.이 문제는 일회성 스크립트에서 모델을 사용하는 경우와 같이 이러한 보기 기능(또는 다른 콜백) 밖에서만 발생합니다.
해결 방법은 애플리케이션 컨텍스트를 직접 푸시하는 것입니다. 이 작업은 다음 작업을 통해 수행할 수 있습니다.
from myapp import app, db
# Set up models
with app.app_context():
db.create_all()
프로그램.app
둘 이상의 애플리케이션이 있을 수 있음을 기억하십시오.
테스트
스택을 조작하려는 또 다른 경우는 테스트용입니다.요청을 처리하는 단위 테스트를 생성하고 결과를 확인할 수 있습니다.
import unittest
from flask import request
class MyTest(unittest.TestCase):
def test_thing(self):
with app.test_request_context('/?next=http://example.com/') as ctx:
# You can now view attributes on request context stack by using `request`.
# Now the request context stack is empty
이전 답변에서는 이미 요청 중 플라스크의 배경에서 진행되는 작업에 대해 좋은 개요를 제공합니다.아직 읽지 않으셨다면 이 글을 읽기 전에 @Mark Hildreth의 답변을 추천합니다.즉, 각 http 요청에 대해 새 컨텍스트(스레드)가 생성되므로 스레드가 필요합니다.Local
다과같은물허시설용는하체를과 같은 을 허용하는 request
그리고.g
요청별 컨텍스트를 유지하면서 스레드 전체에서 전체적으로 액세스할 수 있습니다.또한 http 요청을 처리하는 동안 Flask는 내부에서 추가 요청을 에뮬레이트할 수 있으므로 각각의 컨텍스트를 스택에 저장해야 합니다.또한 Flask를 사용하면 단일 프로세스 내에서 여러 wsgi 응용프로그램을 서로 실행할 수 있으며, 요청 중에 둘 이상의 작업을 호출할 수 있습니다(각 요청이 새 응용프로그램 컨텍스트를 생성함). 따라서 응용프로그램을 위한 컨텍스트 스택이 필요합니다.이전 답변에서 다룬 내용을 요약한 것입니다.
제 목표는 플라스크와 Werkzeug가 이러한 상황에 맞는 현지인들과 어떻게 하는지 설명함으로써 현재의 이해를 보완하는 것입니다.코드의 논리에 대한 이해를 높이기 위해 코드를 단순화했지만, 이것을 알게 되면 실제 소스에 있는 대부분의 내용을 쉽게 파악할 수 있을 것입니다(werkzeug.local
그리고.flask.globals
).
먼저 Werkzeug가 스레드 Local을 구현하는 방법에 대해 알아보겠습니다.
현지의
http 요청이 들어오면 단일 스레드의 컨텍스트 내에서 처리됩니다.Werkzeug는 http 요청 중에 새로운 컨텍스트를 생성하는 대안으로 일반 스레드 대신 그린렛(일종의 가벼운 "마이크로 스레드")을 사용할 수도 있습니다.그린렛이 설치되어 있지 않으면 대신 스레드를 사용하는 것으로 돌아갑니다.는 각각 ID로 할 수 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " 을 할 수 .get_ident()
기능.그 기능이 마법의 시작점입니다.request
,current_app
,url_for
,g
기타 컨텍스트 바운드 글로벌 객체.
try:
from greenlet import get_ident
except ImportError:
from thread import get_ident
어떤 알 수 수 .Local
전체적으로 액세스할 수 있지만 해당 특성에 액세스할 때 특정 스레드의 값으로 확인됩니다.
# globally
local = Local()
# ...
# on thread 1
local.first_name = 'John'
# ...
# on thread 2
local.first_name = 'Debbie'
값 액세스할 수 있는 두값모글하액게에 .Local
만 체개, 동에액세에 .local.first_name
스레드 1의 맥락 안에서 당신에게 줄 것입니다.'John'
반면에 그것은 돌아올 것입니다.'Debbie'
2번 스레드에서
어떻게 그것이 가능한가요?몇 가지 (간체) 코드를 살펴보겠습니다.
class Local(object)
def __init__(self):
self.storage = {}
def __getattr__(self, name):
context_id = get_ident() # we get the current thread's or greenlet's id
contextual_storage = self.storage.setdefault(context_id, {})
try:
return contextual_storage[name]
except KeyError:
raise AttributeError(name)
def __setattr__(self, name, value):
context_id = get_ident()
contextual_storage = self.storage.setdefault(context_id, {})
contextual_storage[name] = value
def __release_local__(self):
context_id = get_ident()
self.storage.pop(context_id, None)
local = Local()
위의 코드에서 우리는 마법이 다음과 같이 요약된다는 것을 알 수 있습니다.get_ident()
현재 그린렛 또는 스레드를 식별합니다. 그Local
스토리지는 이를 키로 사용하여 현재 스레드와 관련된 모든 데이터를 저장합니다.
은 여러 개의 개가수있다니를 수 .Local
수 및 프로세스 수request
,g
,current_app
그리고 다른 것들은 단순히 그렇게 만들어졌을 수도 있습니다.하지만 플라스크에서는 그런 식으로 진행되지 않습니다. 플라스크에서는 기술적으로 그렇지 않습니다. Local
더는 물들나, 그러더게정하확.LocalProxy
물건들.뭐가LocalProxy
?
로컬 프록시
는 LocalProxy를 입니다.Local
다른 관심 대상(즉, 대상이 프록시하는 대상)을 찾습니다.이해하기 위해 살펴보도록 하겠습니다.
class LocalProxy(object):
def __init__(self, local, name):
# `local` here is either an actual `Local` object, that can be used
# to find the object of interest, here identified by `name`, or it's
# a callable that can resolve to that proxied object
self.local = local
# `name` is an identifier that will be passed to the local to find the
# object of interest.
self.name = name
def _get_current_object(self):
# if `self.local` is truly a `Local` it means that it implements
# the `__release_local__()` method which, as its name implies, is
# normally used to release the local. We simply look for it here
# to identify which is actually a Local and which is rather just
# a callable:
if hasattr(self.local, '__release_local__'):
try:
return getattr(self.local, self.name)
except AttributeError:
raise RuntimeError('no object bound to %s' % self.name)
# if self.local is not actually a Local it must be a callable that
# would resolve to the object of interest.
return self.local(self.name)
# Now for the LocalProxy to perform its intended duties i.e. proxying
# to an underlying object located somewhere in a Local, we turn all magic
# methods into proxies for the same methods in the object of interest.
@property
def __dict__(self):
try:
return self._get_current_object().__dict__
except RuntimeError:
raise AttributeError('__dict__')
def __repr__(self):
try:
return repr(self._get_current_object())
except RuntimeError:
return '<%s unbound>' % self.__class__.__name__
def __bool__(self):
try:
return bool(self._get_current_object())
except RuntimeError:
return False
# ... etc etc ...
def __getattr__(self, name):
if name == '__members__':
return dir(self._get_current_object())
return getattr(self._get_current_object(), name)
def __setitem__(self, key, value):
self._get_current_object()[key] = value
def __delitem__(self, key):
del self._get_current_object()[key]
# ... and so on ...
__setattr__ = lambda x, n, v: setattr(x._get_current_object(), n, v)
__delattr__ = lambda x, n: delattr(x._get_current_object(), n)
__str__ = lambda x: str(x._get_current_object())
__lt__ = lambda x, o: x._get_current_object() < o
__le__ = lambda x, o: x._get_current_object() <= o
__eq__ = lambda x, o: x._get_current_object() == o
# ... and so forth ...
이제 글로벌하게 액세스할 수 있는 프록시를 만들려면
# this would happen some time near application start-up
local = Local()
request = LocalProxy(local, 'request')
g = LocalProxy(local, 'g')
그리고 이제 요청 과정 초기에 이전에 생성된 프록시가 액세스할 수 있는 로컬 내부의 일부 개체를 저장합니다. 어떤 스레드에 있든 상관없습니다.
# this would happen early during processing of an http request
local.request = RequestContext(http_environment)
local.g = SomeGeneralPurposeContainer()
를 사용하는 LocalProxy
수 있는 보다는 객체로 할 수 있습니다.Locals
그 자체가 관리를 단순화한다는 것입니다.당신은 단지 싱글만 있으면 됩니다.Local
전역적으로 액세스할 수 있는 프록시를 많이 만드는 개체입니다. 정리 의 파일을 해제하기만 하면 됩니다.Local
쓰지 수 여전히 ("context_id" pop)에 프록시는 여전히 글로벌하게 액세스할 수 있으며 프록시에 종속됩니다.Local
후속 http 요청에 대한 관심 대상을 찾습니다.
# this would happen some time near the end of request processing
release(local) # aka local.__release_local__()
생을단려면 과 같이 하십시오.LocalProxy
우리가 이미 가지고 있을 때.Local
는 Werkzeug를 합니다.Local.__call__()
마법 방법은 다음과 같습니다.
class Local(object):
# ...
# ... all same stuff as before go here ...
# ...
def __call__(self, name):
return LocalProxy(self, name)
# now you can do
local = Local()
request = local('request')
g = local('g')
.request
,g
,current_app
그리고.session
는 우리가했듯이 (단에서) 개의 "할 수 , 그 컨텍스트도 수 있습니다.우리가 확립한 바와 같이, 플라스크는 (단 하나의 실제 http 요청에서) 여러 개의 "가짜" 요청을 생성할 수 있으며, 그 과정에서 여러 개의 애플리케이션 컨텍스트도 푸시할 수 있습니다.이는 일반적인 사용 사례는 아니지만 프레임워크의 기능입니다.이러한 "동시적" 요청과 앱은 여전히 언제든지 "초점"이 있는 하나만 실행하도록 제한되므로, 각 컨텍스트에 스택을 사용하는 것이 타당합니다.새 요청이 생성되거나 애플리케이션 중 하나가 호출될 때마다 각 스택의 맨 위에 컨텍스트가 푸시됩니다.는 플스크용도를 합니다.LocalStack
이 목적을 위한 객체.그들이 사업을 마무리할 때, 그들은 맥락을 스택에서 끌어냅니다.
로컬 스택
이것이 바로LocalStack
처럼 보입니다(코드는 논리를 쉽게 이해할 수 있도록 단순화되었습니다).
class LocalStack(object):
def __init__(self):
self.local = Local()
def push(self, obj):
"""Pushes a new item to the stack"""
rv = getattr(self.local, 'stack', None)
if rv is None:
self.local.stack = rv = []
rv.append(obj)
return rv
def pop(self):
"""Removes the topmost item from the stack, will return the
old value or `None` if the stack was already empty.
"""
stack = getattr(self.local, 'stack', None)
if stack is None:
return None
elif len(stack) == 1:
release_local(self.local) # this simply releases the local
return stack[-1]
else:
return stack.pop()
@property
def top(self):
"""The topmost item on the stack. If the stack is empty,
`None` is returned.
"""
try:
return self.local.stack[-1]
except (AttributeError, IndexError):
return None
은 a 에서언바같이와a입니다.LocalStack
로컬에 저장된 스택이지, 스택에 저장된 로컬의 묶음이 아닙니다.이는 스택이 전체적으로 액세스할 수 있지만 각 스레드에서 서로 다른 스택임을 의미합니다.
플라스크는 그것을 가지고 있지 않습니다.request
,current_app
,g
,그리고.session
는 "" " " " 로 확인LocalStack
그것은 오히려 사용합니다.LocalProxy
룩업 함수를 래핑하는 객체(대신)Local
object에서 기본 를 찾을 수 .LocalStack
:
_request_ctx_stack = LocalStack()
def _find_request():
top = _request_ctx_stack.top
if top is None:
raise RuntimeError('working outside of request context')
return top.request
request = LocalProxy(_find_request)
def _find_session():
top = _request_ctx_stack.top
if top is None:
raise RuntimeError('working outside of request context')
return top.session
session = LocalProxy(_find_session)
_app_ctx_stack = LocalStack()
def _find_g():
top = _app_ctx_stack.top
if top is None:
raise RuntimeError('working outside of application context')
return top.g
g = LocalProxy(_find_g)
def _find_app():
top = _app_ctx_stack.top
if top is None:
raise RuntimeError('working outside of application context')
return top.app
current_app = LocalProxy(_find_app)
이 모든 것은 애플리케이션 시작 시 선언되지만, 요청 컨텍스트 또는 애플리케이션 컨텍스트가 각각의 스택에 푸시될 때까지 실제로 아무것도 해결되지 않습니다.
여러분이 어떤 맥락이 그 후에 ) , ▁in▁if,▁look면▁is다▁a궁),하금▁how▁context▁(스▁out▁stack▁you,flask.app.Flask.wsgi_app()
앱의 웹 할 때 이며, wsgi 앱즉의이다("wsgi", "http 경환것호을전")의 . 그리고 다음의 생성을 따릅니다.RequestContext
는 후속 반대내내▁its까지 .push()
안으로_request_ctx_stack
일단 스택의 맨 위에서 밀면 다음을 통해 액세스할 수 있습니다._request_ctx_stack.top
다음은 흐름을 보여주는 몇 가지 약어 코드입니다.
앱을 시작하고 WSGI 서버에서 사용할 수 있도록 설정합니다.
app = Flask(*config, **kwconfig)
# ...
나중에 http 요청이 들어오고 WSGI 서버가 일반적인 매개 변수를 사용하여 앱을 호출합니다.
app(environ, start_response) # aka app.__call__(environ, start_response)
이것은 대략 앱에서 일어나는 일입니다...
def Flask(object):
# ...
def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)
def wsgi_app(self, environ, start_response):
ctx = RequestContext(self, environ)
ctx.push()
try:
# process the request here
# raise error if any
# return Response
finally:
ctx.pop()
# ...
RequestContext는 대략 이렇게 됩니다.
class RequestContext(object):
def __init__(self, app, environ, request=None):
self.app = app
if request is None:
request = app.request_class(environ)
self.request = request
self.url_adapter = app.create_url_adapter(self.request)
self.session = self.app.open_session(self.request)
if self.session is None:
self.session = self.app.make_null_session()
self.flashes = None
def push(self):
_request_ctx_stack.push(self)
def pop(self):
_request_ctx_stack.pop()
하면, "" " " " " 를 합니다. 다음에 대한 조회가 완료되었습니다.request.path
따라서 보기 기능 중 하나는 다음과 같습니다.
- 액세스할 수 있는 " ▁the▁from다"에서 시작합니다.
LocalProxy
request
. - 을 위해 검색 를 함프고하기를는관본개 (심체중개체인다니찾습)검색시라고 합니다.
_find_request()
()입니다self.local
). - 는 그함는다쿼니다합리를 .
LocalStack
_request_ctx_stack
스택의 맨 위 컨텍스트에 사용할 수 있습니다. - 위의 , 상단컨를위해찾기트텍스▁to,,▁the위,
LocalStack
의 개가먼저내쿼부리합다니를체에 대해 .Local
속성)self.local
) 의stack
이전에 저장된 속성입니다. stack
그것은 최고의 맥락을 얻습니다.- 그리고.
top.request
따라서 기본적인 관심 대상으로 해결됩니다. - 우리는 그 물체로부터 얻습니다.
path
속성
그래서 우리는 어떻게Local
,LocalProxy
,그리고.LocalStack
일, 이제 검색에 대한 의미와 뉘앙스를 잠시 생각해 보십시오.path
사람보내기:
- a
request
전역적으로 액세스할 수 있는 단순한 개체입니다. - a
request
로컬일 수 있는 개체입니다. - a
request
로컬의 특성으로 저장된 개체입니다. - a
request
로컬에 저장된 개체에 대한 프록시인 개체입니다. - a
request
스택에 저장된 개체, 즉 로컬에 저장됩니다. - a
request
로컬에 저장된 스택의 개체에 대한 프록시인 개체입니다.<- 플라스크가 하는 일입니다.
약간의 추가 @마크 힐드레스의 대답.
모양{thread.get_ident(): []}
서, 디에어[]
"stack"은 "stack"만 .append
(push
),pop
그리고.[-1]
(__getitem__(-1)
또는 스레드에 합니다.따라서 컨텍스트 스택은 스레드 또는 그린릿 스레드에 대한 실제 데이터를 유지합니다.
current_app
,g
,request
,session
은 등은입니다.LocalProxy
특수 메소드를 입니다.__getattr__
,__getitem__
,__call__
,__eq__
context top에서 되는 값 (및컨텍트반등값환상의단스택스값▁from(▁value▁and등반▁context▁(환▁return▁stack▁top▁etc의▁and)[-1]
이름 )에 current_app
,request
예를 들어). LocalProxy
이 개체를 한 번 가져오면 실제 개체를 놓치지 않습니다.그러니 그냥 수입하는 게 낫습니다.request
사용자가 코드에 있는 곳이면 어디든 대신 요청 인수를 함수와 메서드로 보내는 놀이를 합니다.당신은 그것으로 쉽게 확장자를 작성할 수 있지만, 경솔한 사용은 코드를 더 이해하기 어렵게 만들 수 있다는 것을 잊지 마세요.
https://github.com/mitsuhiko/werkzeug/blob/master/werkzeug/local.py 을 이해하는 데 시간을 할애합니다.
그렇다면 두 스택 모두 어떻게 채워집니까? 시Flask
:
- 를 만들다
request_context
환별경in(in))map_adapter
path를 합니다. - 이 요청 입력 또는 푸시:
request_context
- 를 만들다
app_context
컨텍스트 스택을 에는 다음과 같이 . - 이 요청을 요청 컨텍스트 스택에 푸시했습니다.
- 세션에서 누락된 경우
- 발송요청서
- 요청 지우기 및 스택에서 팝업
예를 들어, 로컬 및 로컬 프록시의 플라스크 구조를 사용하여 사용자 컨텍스트를 설정하려고 합니다.
하나의 사용자 클래스 정의:
class User(object):
def __init__(self):
self.userid = None
현재 스레드 또는 그린릿 내부의 사용자 개체를 검색하는 함수 정의
def get_user(_local):
try:
# get user object in current thread or greenlet
return _local.user
except AttributeError:
# if user object is not set in current thread ,set empty user object
_local.user = User()
return _local.user
이제 로컬 프록시 정의
usercontext = LocalProxy(partial(get_user, Local()))
현재 스레드 usercontext.userid에서 사용자의 사용자 ID를 가져옵니다.
설명:
로컬에는 ID와 개체에 대한 딕트가 있습니다.ID가 스레드 ID 또는 그린릿 ID입니다.예에서는, 이예서는에,는,
_local.user = User()
._local.___storage__[current thread's id] ["user"] = User()
LocalProxy는 작업을 랩핑된 Local 객체에 위임하거나 대상 객체를 반환하는 함수를 제공할 수 있습니다.위의 예에서
get_user
를 함는현사제다니공에 합니다.LocalProxy
▁for▁▁you때▁and▁user▁when.userid
타고usercontext.userid
,LocalProxy
의__getattr__
가 먼저 을 합니다.get_user
갖기 위해User
객체를 호출한 체사(사용자)호및을 합니다.getattr(user,"userid")
설정하기userid
User
다음을 수행합니다.usercontext.userid = "user_123"
언급URL : https://stackoverflow.com/questions/20036520/what-is-the-purpose-of-flasks-context-stacks
'programing' 카테고리의 다른 글
Oracle 삭제 쿼리에 시간이 너무 많이 걸림 (0) | 2023.07.13 |
---|---|
일부 경우에만 모델에 대한 장고 오버라이드 저장? (0) | 2023.07.13 |
NOT와 AND를 함께 사용하는 MongoDB (0) | 2023.07.13 |
Apache POI를 사용하여 Excel 차트 생성 (0) | 2023.07.13 |
' 상태를 확인하기 위한 Oracle 빈 상태 (0) | 2023.07.13 |