FastAPI + React로 회원관리 시스템 구축 (MySQL 연동)

2025. 5. 21. 13:46·Python

FastAPI + React로 회원관리 시스템 구축 (MySQL 연동)

MySQL 설치

아래 링크를 참고하여 MySQL과 Workbench를 설치합니다.
https://myanjini.tistory.com/entry/MySQL-8034-MySQL-Workbench-80-설치

스키마 생성

MySQL Workbench에서 fastapiuser 사용자로 접속한 상태에서 아래 쿼리를 실행합니다.

CREATE SCHEMA `fastapidb` DEFAULT CHARACTER SET utf8;

실행이 완료되면 왼쪽 SCHEMAS 목록에서 fastapidb가 생성된 것을 확인할 수 있습니다.

MySQL 연동 설정 (database/connection.py)

# 데이터베이스 설정
from sqlmodel import SQLModel, create_engine, Session

# MySQL + PyMySQL 연결 문자열 (@는 %40으로 인코딩)
database_connection_string = "mysql+pymysql://fastapiuser:p%40ssw0rd@localhost:3306/fastapidb"

engine_url = create_engine(
    database_connection_string,
    echo=True  # SQL 쿼리 로그 확인용
)

# 테이블 생성 함수
def conn():
    SQLModel.metadata.create_all(engine_url)

# 세션 제공 함수
def get_session():
    with Session(engine_url) as session:
        yield session

 

 

 

데이터베이스 연결 정보를 별도 파일(.env)에서 읽어오도록 수정

프로젝트 설정 정보를 코드에 직접 작성하는 대신, .env 파일을 통해 외부에서 관리하도록 수정할 수 있습니다.
이를 통해 보안성과 유지보수성이 향상되며, 실무에서도 가장 권장되는 방식입니다.

 pydantic-settings 설치

pip install pydantic-settings
pip freeze > requirements.txt

 .env 파일 생성 (루트 경로)

# .env 파일 내용
DATABASE_URL=mysql+pymysql://fastapiuser:p%40ssw0rd@localhost:3306/fastapidb

 database/connection.py 코드 수정

from typing import Optional
from pydantic_settings import BaseSettings
from sqlmodel import SQLModel, create_engine, Session

# .env에서 설정값 로드
class Settings(BaseSettings):
    DATABASE_URL: Optional[str] = None

    class Config:
        env_file = ".env"  # 오타 주의: evn_file ❌

settings = Settings()

# 연결 문자열은 .env에서 불러온 값으로 대체
engine_url = create_engine(
    settings.DATABASE_URL,
    echo=True,
)

# 테이블 생성 함수
def conn():
    SQLModel.metadata.create_all(engine_url)

# 세션 제공 함수
def get_session():
    with Session(engine_url) as session:
        yield session

settings.DATABASE_URL이 None일 경우를 대비해 중간에 아래와 같은 디버깅 코드를 추가하는 것도 좋습니다.

print("📌 현재 DATABASE_URL =", settings.DATABASE_URL)

환경 파일(.env)을 사용하면 실제 배포 환경이나 로컬 환경에서 서로 다른 DB 연결 정보를 유연하게 적용할 수 있습니다.

순환 참조 방지 (TYPE_CHECKING 사용)

models.users와 models.events처럼 서로를 참조하는 구조에서는 순환 참조가 발생할 수 있습니다.
이를 방지하기 위해 TYPE_CHECKING을 사용하여 타입 힌트만 인식되도록 처리합니다.

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from models.events import Event  # 또는 반대로 from models.users import User

📁 models/events.py

from typing import TYPE_CHECKING, List, Optional
from sqlmodel import SQLModel, Field, Relationship

if TYPE_CHECKING:
    from models.users import User

class Event(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    title: str
    image: str
    description: str
    tags: Optional[str]  # JSON 대신 str로 저장
    location: str

    user_id: Optional[int] = Field(default=None, foreign_key="user.id")
    user: Optional["User"] = Relationship(back_populates="events")

📁 models/users.py

from typing import TYPE_CHECKING, List, Optional
from pydantic import EmailStr
from sqlmodel import SQLModel, Field, Relationship

if TYPE_CHECKING:
    from models.events import Event

class User(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    email: EmailStr
    password: str
    username: str

    events: List["Event"] = Relationship(back_populates="user")

관계 설정: Relationship(back_populates)

두 모델 간의 관계를 정의할 때 사용하는 Relationship()은 실제 DB 컬럼을 생성하지 않으며, ORM 객체 간의 연결을 위한 속성입니다.
양쪽에서 back_populates 이름을 서로 일치시켜야 관계가 올바르게 작동합니다.

# models/users.py
events: List["Event"] = Relationship(back_populates="user")

# models/events.py
user: Optional["User"] = Relationship(back_populates="events")

※ 이 필드는 실제 테이블에는 존재하지 않으며, 파이썬 코드 상에서만 작동합니다.

SQLModel의 Relationship과 Optional 필드 동작

FastAPI + SQLModel 환경에서 자주 마주치는 개념 두 가지를 정리합니다.

  • Relationship은 테이블 컬럼이 아닌 객체 간 연결용 필드
  • Optional 필드는 테이블에 생성되지만 NULL 허용

① Relationship은 실제 컬럼이 아니다

class User(SQLModel, table=True):
    events: List["Event"] = Relationship(back_populates="user")

위 코드는 객체 간 연결을 위한 설정이며, 실제 DB에는 events 컬럼이 존재하지 않습니다.

② 외래키는 관계의 반대쪽에서 정의

class Event(SQLModel, table=True):
    user_id: Optional[int] = Field(default=None, foreign_key="user.id")
    user: Optional["User"] = Relationship(back_populates="events")

실제 외래키 컬럼(user_id)은 event 테이블에 생성되며, 관계의 기준이 됩니다.

③ Optional 필드의 동작 방식

description: Optional[str] = None  # → DB에서는 DEFAULT NULL

Optional로 선언된 필드는 DB에서 NULL 허용 컬럼으로 생성되며, 값이 없을 경우 NULL이 저장됩니다.

요약

  • Relationship()은 ORM 전용 필드, 실제 DB 컬럼 X
  • 외래키 컬럼은 관계를 맺는 반대쪽 모델에 정의
  • back_populates는 양방향 관계 매핑에 필수
  • Optional은 선택 입력 필드이며 NULL 허용

'Python' 카테고리의 다른 글

FastAPI에서 JWT 토큰을 이용한 로그인 인증 구현  (0) 2025.05.21
React와 Python 연결  (0) 2025.05.20
FastAPI-DB연결  (0) 2025.05.18
FastAPI-CRUD  (0) 2025.05.16
Path, Query, Response_model  (0) 2025.05.15
FastAPI 백엔드 개발 환경 세팅 & 기본 API 구현 정리  (0) 2025.05.14
'Python' 카테고리의 다른 글
  • FastAPI에서 JWT 토큰을 이용한 로그인 인증 구현
  • React와 Python 연결
  • FastAPI-DB연결
  • FastAPI-CRUD
jaeon.cloud
jaeon.cloud
  • jaeon.cloud
    JEONG JAE ON
    jaeon.cloud
  • 전체
    오늘
    어제
    • 분류 전체보기 (60)
      • Docker (8)
      • Cloud (7)
      • AWS (14)
      • Network (9)
      • Linux (1)
      • Python (7)
      • Javascript (3)
      • React (5)
      • Project (3)
      • Kubernetes (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • GitHub
  • 공지사항

  • 인기 글

  • 태그

    클라우드
    kubernetes
    react
    http
    AWS
    lambda
    Python
    cors
    docker
    3-tier Architecture
    네트워크
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
jaeon.cloud
FastAPI + React로 회원관리 시스템 구축 (MySQL 연동)
상단으로

티스토리툴바