Flask 앱 팩토리 — 애플리케이션 생성 함수

Flask 앱 팩토리 — 애플리케이션 생성 함수

이미 패키지와 블루프린트를 쓰고 있다면(Modular Applications with Blueprints), 경험을 더 좋게 만드는 몇 가지 방법이 있어요. 흔한 패턴은 블루프린트가 import 될 때 앱 객체를 만드는 것이에요. 하지만 이 객체 생성을 함수 안으로 옮기면, 나중에 이 앱의 여러 인스턴스를 만들 수 있어요.

출처: Application Factories — Flask Documentation

왜 이런 방식을 쓰고 싶을까요? 두 가지 이유가 있어요.

  1. 테스팅 — 서로 다른 설정을 가진 앱 인스턴스를 만들어 모든 경우를 테스트할 수 있어요.
  2. 여러 인스턴스 — 같은 앱의 다른 버전을 실행하고 싶다면, 웹서버에서 여러 config를 가진 인스턴스를 만들 수도 있지만, 팩토리를 쓰면 같은 앱 프로세스 안에서 같은 애플리케이션의 여러 인스턴스를 띄울 수 있어요.

그럼 어떻게 구현할까요?

기본 팩토리

아이디어는 함수 안에서 앱을 셋업하는 거예요.

def create_app(config_filename):
    app = Flask(__name__)
    app.config.from_pyfile(config_filename)

    from yourapplication.model import db
    db.init_app(app)

    from yourapplication.views.admin import admin
    from yourapplication.views.frontend import frontend
    app.register_blueprint(admin)
    app.register_blueprint(frontend)

    return app

단점은 블루프린트를 import 할 때 앱 객체를 쓸 수 없다는 것이에요. 하지만 요청 안에서는 쓸 수 있어요. 설정이 있는 앱에 어떻게 접근할까요? current_app을 쓰면 돼요.

from flask import current_app, Blueprint, render_template

admin = Blueprint('admin', __name__, url_prefix='/admin')

@admin.route('/')
def index():
    return render_template(current_app.config['INDEX_TEMPLATE'])

여기서 설정에서 템플릿 이름을 찾아와요.

팩토리와 확장

확장과 앱 팩토리를 만들 때, 확장 객체가 처음부터 앱에 바인딩되지 않도록 하는 것이 좋아요. Flask-SQLAlchemy를 예로 들면, 이런 방식은 피해야 해요.

def create_app(config_filename):
    app = Flask(__name__)
    app.config.from_pyfile(config_filename)

    db = SQLAlchemy(app)

대신, model.py(또는 그에 준하는)에서는 이렇게 두고:

db = SQLAlchemy()

application.py(또는 그에 준하는)의 create_app에서는 db.init_app(app)으로 연결해요.

def create_app(config_filename):
    app = Flask(__name__)
    app.config.from_pyfile(config_filename)

    from yourapplication.model import db
    db.init_app(app)

이 디자인 패턴을 쓰면 확장 객체에 앱별 상태가 저장되지 않아서, 하나의 확장 객체를 여러 앱에 쓸 수 있어요.

앱 실행하기

팩토리로 만든 앱은 flask 명령으로 실행할 수 있어요.

$ flask --app hello run

Flask는 팩토리 이름이 hello 안의 create_app이나 make_app이면 자동으로 감지해요. 팩토리에 인자를 전달할 수도 있어요.

$ flask --app 'hello:create_app(local_auth=True)' run

그러면 hellocreate_app 팩토리가 local_auth=True 키워드 인자로 호출돼요.

정리하면, 앱 팩토리는 "앱 생성을 함수로 만들어 여러 설정·여러 인스턴스로 재사용"하는 패턴이에요. 확장은 미리 바인딩하지 않고 init_app(app)으로 연결하고, 블루프린트 안에서는 current_app으로 앱에 접근해요.

더 알아보기