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