FastAPIでアプリ起動時に管理者ユーザを自動生成する
fastapi.FastAPI()
のlifespan
パラメータを利用して、アプリ起動時および終了時の処理を実行できる。
https://fastapi.tiangolo.com/advanced/events/?h=lifespan#lifespan
これを応用して、アプリ起動時に、DBに存在しなければ管理者ユーザを生成する、という処理を実現可能。
@asynccontextmanager
async def lifespan(app: FastAPI):
"""アプリケーションの起動・終了時に実行される処理を定義するコンテキストマネージャ."""
try:
# Adminユーザが存在しない場合は作成する
is_created = create_super_user()
if is_created:
logger.info("Admin user created successfully.")
else:
logger.info("Admin user already exists.")
except Exception:
logger.exception("Failed to create admin user.")
raise
yield
app = FastAPI(lifespan=lifespan)
def create_super_user() -> bool:
"""スーパーユーザを作成する.
Returns:
bool: スーパーユーザが作成された場合はTrue, 既に存在する場合はFalse.
"""
db = next(get_db())
# ADMIN_EMAILを持つAdminUserが存在する場合はスキップ
if db.query(AdminUser).filter(AdminUser.email == ADMIN_EMAIL).first():
return False
# ユーザー名、メールアドレス、パスワードを指定してAdminUserを作成
admin_user = AdminUser(
username=ADMIN_USERNAME,
email=ADMIN_EMAIL,
hashed_password=ADMIN_PASSWORD,
)
db.add(admin_user)
db.commit()
return True
参考までに、get_db()
は以下のように実装している。
from typing import Generator
from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker
from libs.constants import DATABASE_URL
IS_POSTGRESQL = "postgresql" in DATABASE_URL
# SQLAlchemy エンジンの作成
engine = create_engine(
DATABASE_URL,
connect_args={"check_same_thread": False}
if DATABASE_URL.startswith("sqlite")
else {},
)
# セッションの作成
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
def get_db() -> Generator[Session, None, None]:
"""SQLAlchemy セッションを取得するジェネレータ関数."""
db = SessionLocal()
try:
yield db
finally:
db.close()

oddy
"チーバくんの目"のあたりで暮らす、フリーランスエンジニアのoddyです。 サイト名の"OJTHON"(オジソン)の由来は、わが家での私のあだ名とプログラミング言語Python(パイソン)のもじりです。 僕たち家族の思い出と記録、そして今の僕が考えることについて、何かしらの形にして残していきたいと思い、このOJTHON.dev HOME / BLOGを作りました。