쿼카러버의 기술 블로그

[Flask] Flask의 context 간단 정리 (application context, request context) 본문

[Python]

[Flask] Flask의 context 간단 정리 (application context, request context)

quokkalover 2022. 1. 31. 00:42

Flask로 웹서버를 구현하다보면 context라는 개념을 접하게 된다. 어떻게 보면 핵심 개념인데, 엄청 헷갈리고 잘 이해가 되지 않아서 고생하고 있던 찰나에, 아주 잘 정리된 글을 발견했다. 해당 글을 번역하고, 내가 이해하기 쉬운 방식으로 재구성해 정리했다. 필자가 추천하는 flask의 context 학습방법은 아래와 같다.

flask의 context 학습방법

1) 이 글을 읽는다.

2) 다음 링크의 글을 읽고 context와 flask의 request처리의 전반적인 흐름을 파악한다.

 

먼저 간단하게 이번 글의 주제인 flask context에 대한 간단 분석을 시작해보자!

Context란?

어떤 Task를 수행할 때 수행상태 및 정보를 를 기억하기 위해서 Task마다 코드 실행과 관련된 정보들을 구성하고 있는 것을 Context라고 한다.

 

Flask에서 Context란?

파이썬으로 웹 개발을 하다보면 주로 장고 혹은 플라스크를 사용한다. 근데 Flask로 개발을 하게되면 다른 웹 프레임워크와는 다른 특징을 하나 볼 수 있는데, 그게 바로 Context다.

Flask에서 context는 request를 처리하거나 CLI 명령어를 처리하기 위해 필요한 정보들을 저장하고 제공하기 위해 사용된다.

그 중 특이한 점은 Flask의 controller function(view function)의 argument로 request object를 받지 않는다는 점이다. 예시로 비교하면 좀 편하다

Django

def users(request):
    if request.method == 'POST':
         # Save the form data to the database
         # Send response
   else:
         # Get all users from the database
         # Send response

Flask

from flask import request

@app.route('/', methods=['GET', 'POST'])
def users():
    if request.method == 'POST':
         # Save the form data to the database
         # Send response
    else:
         # Get all users from the database
         # Send response

Flask의 예제를 보면, request 객체가 전역변수로 사용되는 것 같다. 진짜 flask는 모든 요청에 대해서 request라는 전역변수 하나를 활용할까? 반은 맞고 반은 틀리다.(이게 헷갈리는 포인트) 일단 request객체를 전역변수로 사용할 수는 없다.

일단 멀티 쓰레드 환경으로 어플리케이션이 동작할 때 모든 쓰레드가 같은 request 객체에 접근하게 되면 thread-safe하지 않기 때문이다.

여기서 등장하는 개념이 바로 context다. context를 활용해서 특정 변수를 전역변수처럼 사용하지만, 특정 단위(thread, process, coroutine)만 접근할 수 있다. Flask에서는 이를 context-local이라고 부른다. 이는 파이썬의 thread-local과 유사한 개념이지만 다르다. thread-local은 thread에 한해서만 사용가능하지만, flask의 context-local구현체는 thread, process, coroutine에서 모두 활용가능하기 때문에 더 generic하다.

 

Context의 종류

Flask의 Context는 크게 두 종류가 있다. : Application Context, Request Context

Flask는 요청이 들어오게 되면 이 context들을 생성한다. 각 context들을 활용하는 예시들을 살펴보자.

 

Application Context

1) application level의 data를 보관한다. (logger, database configuration)

2) 아래 두 개의 객체를 외부에 노출시킨다(application context에 접근할 수 있는 proxy 객체)

  • current_app : 현재 request를 핸들링하고 있는 app instance를 참조하고있다 (run()할 때 실행되는 app을 말함)
  • g : request를 처리할때 잠시 temporary 저장소로 사용된다. database config같은 request를 handling할 동안 잠시 저장한다. request가 끝날때마다 g에 있는 데이터는 모두 리셋된다.

 

에러 발생 케이스

from flask import Flask, current_app
current_app.config

# This typically means that you attempted to use functionality that needed
# to interface with the current application object in some way. To solve
# this, set up an application context with app.app_context().  See the
# documentation for more information.

 

정상 동작 케이스

 

view function(controller function)외부에서 application context와 request context에 접근하기 위해서는 먼저 context를 먼저 생성해야 한다.

from app import app
from flask import current_app

app_ctx = app.app_context()
app_ctx.push()

current_app.config["ENV"]
app_ctx.pop()

 

Request Context

1) request level의 data를 보관한다. (URL, HTTP method, request header, session 등)

2) 아래 두 개의 객체를 외부에 노출시킨다. (request context에 접근할 수 있는 proxy 객체)

  • request : 현재 핸들링하고 있는 요청에 대한 정보만을 담고 있다.
  • session : 사전형 자료구조와 비슷한 자료 구조로, cryptographically signed된 정보를 담아둔다. 특정 request에서 다른 request로 정보를 기억할 수 있다. request를 통해 접근할 수 있지만 from flask import session 구문으로 import해서 사용하는게 best practice다.

 

에러 발생 케이스

from flask import Flask, request
request.method

정상 동작 케이스

#without a context manager
from app import app
from flask import request

# test_request_context를 호출하면 request context가 생김 (테스트에 사용됨)
request_ctx = app.test_request_context()
request_ctx.push()
request.method
#'GET'
request.path
#'/'
request_ctx.pop()
#with a context manager
from app import app
from flask import request

with app.test_request_context('/'):
    request.method
    request.path

#'GET'
#'/'

It's worth noting that each of the above objects are often referred to as "proxies". This just means that they are proxies to global flavors of the objects.

 

본 글에서는 Flask에서의 context에 대해 간단히 알아봤다. 이제 이들이 어떻게 활용되고, flask에서 이들을 활용해 요청을 어떻게 처리하는지 디테일하게 알아보고 싶다면 아래 글으로 넘어가자!

 

 

참고자료

https://www.codestudyblog.com/cnb11/1124181719.html

https://testdriven.io/blog/flask-contexts/

https://testdriven.io/blog/flask-contexts-advanced/

https://flask.palletsprojects.com/en/1.1.x/reqcontext/#notes-on-proxies

https://speakerdeck.com/mitsuhiko/advanced-flask-patterns-1

https://en.wikipedia.org/wiki/Context_(computing)

https://www.youtube.com/watch?v=fq8y-9UHjyk

https://www.linkedin.com/pulse/application-context-request-flask-shruthi-sagar-cr/?trk=articles_directory

Comments