Initial commit: add FastAPI MVP (모프) and existing web app
Includes FastAPI+Jinja2+HTMX+SQLite implementation with seed categories, plus deployment templates. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
88
database.py
Normal file
88
database.py
Normal file
@@ -0,0 +1,88 @@
|
||||
"""
|
||||
database.py
|
||||
|
||||
- 기본 DB는 SQLite 파일(`all_prompt.db`)을 사용합니다.
|
||||
- 나중에 PostgreSQL 등으로 바꾸기 쉽도록 `MOPF_DATABASE_URL` 환경변수를 지원합니다.
|
||||
- migration 도구 없이 `create_all()`로 테이블을 자동 생성합니다.
|
||||
|
||||
요구사항에 등장한 원격 DB 정보(참고):
|
||||
host: ncue.net
|
||||
database: all_prompt
|
||||
user: ncue
|
||||
password: (문서/코드에 하드코딩하지 말고 환경변수로 전달 권장)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from typing import Generator
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import Session, sessionmaker
|
||||
|
||||
from models import Base, Category
|
||||
|
||||
|
||||
def _default_sqlite_url() -> str:
|
||||
# 루트에서 `python main.py`를 실행하는 것을 전제로, 현재 작업 디렉토리에 DB 파일이 생성됩니다.
|
||||
return "sqlite:///./all_prompt.db"
|
||||
|
||||
|
||||
# 이 저장소에는 기존(Next.js/Prisma 등)에서 `DATABASE_URL`을 쓰는 코드가 이미 있을 수 있습니다.
|
||||
# 따라서 Python MVP는 충돌을 피하려고 별도의 환경변수명을 사용합니다.
|
||||
DATABASE_URL = os.getenv("MOPF_DATABASE_URL", _default_sqlite_url())
|
||||
|
||||
# SQLite는 멀티스레드에서 같은 커넥션을 공유할 때 옵션이 필요합니다.
|
||||
connect_args = {"check_same_thread": False} if DATABASE_URL.startswith("sqlite") else {}
|
||||
|
||||
engine = create_engine(
|
||||
DATABASE_URL,
|
||||
connect_args=connect_args,
|
||||
future=True,
|
||||
)
|
||||
|
||||
SessionLocal = sessionmaker(
|
||||
bind=engine,
|
||||
autocommit=False,
|
||||
autoflush=False,
|
||||
expire_on_commit=False, # 템플릿 렌더링에서 접근하기 편하게
|
||||
class_=Session,
|
||||
)
|
||||
|
||||
|
||||
def get_db() -> Generator[Session, None, None]:
|
||||
"""FastAPI dependency로 사용하는 DB 세션."""
|
||||
db = SessionLocal()
|
||||
try:
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
DEFAULT_CATEGORIES = [
|
||||
# (name, slug)
|
||||
("글쓰기", "writing"),
|
||||
("코딩", "coding"),
|
||||
("업무 자동화", "automation"),
|
||||
("이미지 생성", "image-generation"),
|
||||
("데이터 분석", "data-analysis"),
|
||||
]
|
||||
|
||||
|
||||
def init_db_and_seed() -> None:
|
||||
"""
|
||||
- 테이블 생성(create_all)
|
||||
- 초기 카테고리 seed(이미 있으면 건너뜀)
|
||||
"""
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
||||
db = SessionLocal()
|
||||
try:
|
||||
existing = db.query(Category).count()
|
||||
if existing == 0:
|
||||
for name, slug in DEFAULT_CATEGORIES:
|
||||
db.add(Category(name=name, slug=slug))
|
||||
db.commit()
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
Reference in New Issue
Block a user