Flask 프로젝트 구조 설정 가이드

Flask는 Django와 달리 프로젝트 생성 시 자동으로 디렉터리 구조를 제공하지 않기 때문에, 개발자가 직접 프로젝트 구조를 구성해야 한다. 아래는 모듈화된 Flask 애플리케이션을 위한 일반적인 디렉터리 구조와 핵심 구성 요소 예시이다.

디렉터리 구조

  • app/ – 주요 애플리케이션 로직
  • utils/ – 유틸리티 모듈 (예: DB 연결 풀)
  • manage.py – 서버 실행 및 CLI 명령 정의
  • settings.py – 환경별 설정
  • auth/ – 인증 관련 로직

애플리케이션 팩토리 (app/__init__.py)

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from auth.auth import Auth

# 블루프린트 임포트
from .views.account import account_bp
from .views.main import main_bp
from .views.user import user_bp

# SQLAlchemy 인스턴스 생성
db = SQLAlchemy()

def create_app():
    app = Flask(__name__)
    app.debug = True
    app.secret_key = 'your-secret-key-here'
    
    # 설정 로드
    app.config.from_object('settings.DevelopmentConfig')
    
    # 블루프린트 등록
    app.register_blueprint(account_bp)
    app.register_blueprint(main_bp)
    app.register_blueprint(user_bp)
    
    # 확장 기능 초기화
    Auth(app)
    db.init_app(app)
    
    return app

관리 스크립트 (manage.py)

import os
from flask_script import Manager, Server
from flask_migrate import Migrate, MigrateCommand
from app import create_app, db

app = create_app()
manager = Manager(app)
migrate = Migrate(app, db)

@manager.command
def custom(arg):
    print(f"Custom arg: {arg}")

@manager.option('-n', '--name', dest='name')
@manager.option('-u', '--url', dest='url')
def cmd(name, url):
    print(f"Name: {name}, URL: {url}")

manager.add_command('db', MigrateCommand)
manager.add_command("runserver", Server())

if __name__ == "__main__":
    manager.run()

환경 설정 (settings.py)

class BaseConfig:
    SESSION_TYPE = 'redis'
    SESSION_KEY_PREFIX = 'session:'
    SESSION_PERMANENT = False
    SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:123@127.0.0.1:3306/flask_cata?charset=utf8"
    SQLALCHEMY_POOL_SIZE = 2
    SQLALCHEMY_POOL_TIMEOUT = 30
    SQLALCHEMY_TRACK_MODIFICATIONS = False

class DevelopmentConfig(BaseConfig):
    pass

class ProductionConfig(BaseConfig):
    pass

데이터베이스 연결 풀 (utils/pool/db_pool.py)

from DBUtils.PooledDB import PooledDB
import pymysql

POOL = PooledDB(
    creator=pymysql,
    maxconnections=6,
    mincached=2,
    maxcached=5,
    blocking=True,
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123',
    database='flask_cata',
    charset='utf8'
)

SQL 도우미 클래스 (utils/pool/sqlhelper.py)

from utils.pool import db_pool
import pymysql

class SQLHelper:
    def __init__(self):
        self.conn = None
        self.cursor = None

    def open(self, cursor=pymysql.cursors.DictCursor):
        self.conn = db_pool.POOL.connection()
        self.cursor = self.conn.cursor(cursor=cursor)

    def close(self):
        self.cursor.close()
        self.conn.close()

    def fetchone(self, sql, params):
        self.cursor.execute(sql, params)
        return self.cursor.fetchone()

    def fetchall(self, sql, params):
        self.cursor.execute(sql, params)
        return self.cursor.fetchall()

    def __enter__(self):
        self.open()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()

모델 정의 (app/models.py)

from app import db

class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password = db.Column(db.String(120), nullable=False)

뷰 함수 예시

app/views/account.py

from flask import Blueprint, render_template, request
from app import db, models

account_bp = Blueprint('account', __name__)

@account_bp.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        return render_template('login.html')
    # POST 처리 로직 생략

app/views/main.py

from flask import Blueprint, render_template
from utils.pool.sqlhelper import SQLHelper

main_bp = Blueprint('main', __name__)

@main_bp.route('/index')
def index():
    with SQLHelper() as helper:
        user_list = helper.fetchall('SELECT * FROM users', [])
    return render_template('index.html', user_list=user_list)

템플릿 예시

templates/layout.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}{% endblock %}</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
    {% block css %}{% endblock %}
</head>
<body>
    <div class="container">
        {% block body %}{% endblock %}
    </div>
    {% block js %}{% endblock %}
</body>
</html>

templates/index.html

{% extends 'layout.html' %}

{% block title %}대시보드{% endblock %}

{% block body %}
<h1>환영합니다, {{ session.get('user') }}님!</h1>
<ul>
{% for user in user_list %}
    <li>{{ user.username }}</li>
{% endfor %}
</ul>
{% endblock %}

인증 미들웨어 (auth/auth.py)

from flask import session, redirect, request

class Auth:
    def __init__(self, app=None):
        if app:
            self.init_app(app)

    def init_app(self, app):
        app.auth_manager = self
        app.before_request(self.check_login)
        app.context_processor(self.inject_user)

    def inject_user(self):
        return dict(current_user=session.get('user'))

    def check_login(self):
        if request.endpoint in ('account.login',):
            return
        if not session.get('user'):
            return redirect('/login')

    def login(self, username):
        session['user'] = username

태그: flask Flask-SQLAlchemy Flask-Migrate Blueprint DbUtils

9월 21일 06:42에 게시됨