FastAPI - (2) FastAPI 개발 기초 공사

이영락·2024년 10월 7일

개발자 기본기

목록 보기
36/53

파이썬 개발 기초 공사

🏖️ 2-00 안녕하세요 파이보

이번에는 웹 브라우저에 "안녕하세요 파이보"를 출력해 주는 첫 번째 프로그램을 만들어 보자. 단, 이때 "안녕하세요 파이보"라는 문자열은 Svelte가 FastAPI 서버에 요청하여 돌려받은 값으로 출력할 수 있게 해 보자.


Hello API 만들기

가장 먼저 FastAPI에 Hello API를 만들어 보자. 파이참 에디터에서 다음과 같은 main.py 파일을 작성한다.

from fastapi import FastAPI

app = FastAPI()

@app.get("/hello")
def hello():
    return {"message": "안녕하세요 파이보"}

FastAPI 서버를 실행하기 위해 uvicorn을 설치한다. 터미널에서 아래 명령을 실행한다.

(myapi) c:/projects/myapi> pip install "uvicorn[standard]"

FastAPI 서버 실행

서버를 실행하기 위해 아래 명령어를 실행.

(myapi) c:/projects/myapi> uvicorn main:app --reload

브라우저에서 http://127.0.0.1:8000/docs 주소를 입력하면 FastAPI의 /hello API를 테스트할 수 있다.

Svelte 웹 페이지 만들기

이제 백엔드의 Hello API를 완성했으니 프론트엔드 영역에서 웹 페이지를 만들어 보자. VSCode를 열고 projects/myapi/frontend/src/App.svelte 파일을 열어 디폴트로 작성된 내용을 모두 지우고 다음과 같이 작성하자.

<script>
  let message;

  fetch("http://127.0.0.1:8000/hello").then((response) => {
    response.json().then((json) => {
      message = json.message;
    });
  });
</script>

<h1>{message}</h1>

Svelte는 자바스크립트 변수를 HTML 태그에 중괄호 {}로 출력할 수 있다. 이 코드는 FastAPI의 Hello API를 호출해 받은 데이터를 message 변수에 담고, 그 값을 화면에 출력한다.

CORS 설정

Svelte와 FastAPI 서버 간 통신 중 CORS 오류가 발생할 수 있다. 이를 해결하기 위해 main.py 파일을 아래와 같이 수정하자.

from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware

app = FastAPI()

origins = [
    "http://127.0.0.1:5173",    # 또는 "http://localhost:5173"
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/hello")
def hello():
    return {"message": "안녕하세요 파이보"}

만약 Svelte 서버가 http://localhost:5173으로 실행되었다면 origins에 http://127.0.0.1:5173 대신 http://localhost:5173을 추가하자. 이제 브라우저에서 다시 확인해보면 “안녕하세요 파이보” 메시지가 정상적으로 표시될 것이다.


🏖️ 2-01 FastAPI 기초 다지기

현재 파이보 프로젝트는 projects/myapi 디렉터리 아래에 main.py 파일만 생성한 상태다. 하지만 더 규모가 있는 FastAPI 프로젝트를 만들고자 한다면, 프로젝트 구조를 잘 설계하는 것이 중요하다. 다만, FastAPI는 "프로젝트 구조에 대한 규칙"이 없기 때문에 프로젝트를 구성할 때는 고민이 필요하다.


FastAPI 프로젝트 구조

이번 장에서는 파이보 프로젝트의 전체적인 구조를 먼저 구상해 보자. 이 프로젝트의 목표는 질문과 답변을 관리하는 게시판을 만드는 것이다. 현재는 main.py 파일만 만들어진 상태지만, 전체적으로 프로젝트 구조는 다음과 같아야 한다.

├── main.py
├── database.py
├── models.py
├── domain
│   ├── answer
│   ├── question
│   └── user
└── frontend

main.py 파일

main.py 파일은 FastAPI 프로젝트의 시작점이다. 이 파일에서 FastAPI의 app 객체를 생성하고 프로젝트의 전체적인 환경을 설정한다. 이 app 객체는 FastAPI의 핵심으로, 앱의 전반적인 설정과 API 등록 등이 이 객체를 통해 이루어진다.


database.py 파일

database.py 파일은 데이터베이스와 관련된 설정을 관리하는 파일이다. 여기에는 데이터베이스 접속 정보(주소, 사용자, 비밀번호 등)를 설정하고, 데이터베이스와 연결을 유지하기 위한 다양한 함수와 변수가 포함될 것이다.


models.py 파일

파이보 프로젝트에서는 ORM(Object Relational Mapping) 도구인 SQLAlchemy를 사용할 것이다. SQLAlchemy는 데이터베이스를 모델 기반으로 처리하며, 이 models.py 파일에서는 각 데이터베이스 테이블을 정의하는 모델 클래스들을 작성하게 된다. 모델 클래스는 데이터베이스와의 상호작용을 추상화하여 코드를 더 직관적으로 작성할 수 있게 해준다.


API를 구성하는 domain 디렉터리

domain 디렉터리는 API의 주요 기능을 담당하는 부분이다. 파이보 프로젝트는 게시판 형태의 서비스로, "질문", "답변", "사용자" 라는 3개의 도메인으로 구분할 것이다. 각 도메인은 해당 기능에 관련된 API를 정의하는 역할을 한다.

각 도메인에는 3가지 주요 파일이 필요하다:

  1. 라우터 파일 - API 엔드포인트(URL)와 동작을 정의
  2. 데이터베이스 처리 파일 - CRUD(Create, Read, Update, Delete) 기능 담당
  3. 입출력 관리 파일 - 입력 데이터와 출력 데이터를 검증하고 스펙을 정의

예를 들어 question 도메인에서는 다음과 같은 파일들이 필요하다:

  • question_router.py - 라우터 파일
  • question_crud.py - 데이터베이스 처리 파일
  • question_schema.py - 입출력 관리 파일

이와 같은 구조로 answer 도메인과 user 도메인도 구성하게 될 것이다.


frontend 디렉터리

frontend 디렉터리는 프론트엔드 소스를 관리하는 공간이다. Svelte 프레임워크를 사용해 사용자 인터페이스를 구성할 것이며, 최종적으로 frontend/dist 디렉터리에는 빌드된 파일들이 저장되어 FastAPI 서버에서 제공하게 된다.


아래는 요청하신 형식에 맞춰 정리한 내용입니다. 대단원, 중단원, 소단원 제목에 색깔이 적용되었으며, 각 줄마다 “이다”, “있다” 등을 활용하여 내용을 보기 쉽게 구성했습니다.


🏖️ 2-02 모델로 데이터베이스 관리하기

우리가 만들 파이보는 질문 답변 게시판이다.
질문이나 답변을 작성하면 데이터가 생성된다.
그러므로 데이터를 저장하거나 조회하거나 수정하는 등의 기능을 구현해야 한다.
웹 서비스는 데이터를 처리할 때 대부분 데이터베이스를 사용한다.


데이터베이스와 ORM 소개

데이터베이스를 사용하려면 SQL 쿼리(query)라는 구조화된 질의를 작성하고 실행하는 등의 복잡한 과정이 필요하다.
이때 ORM(object relational mapping)을 이용하면 파이썬 문법만으로도 데이터베이스를 다룰 수 있다.
즉, ORM을 이용하면 개발자가 쿼리를 직접 작성하지 않아도 데이터베이스의 데이터를 처리할 수 있다.
ORM은 데이터베이스에 데이터를 저장하는 테이블을 파이썬 클래스로 만들어 관리하는 기술로 이해해도 좋다.
이 책은 독자가 데이터베이스 개념이나 SQL 쿼리의 기초는 안다고 가정한다.
그러나 독자가 이런 기초지식이 없어도 이 책의 실습을 따라 하고 내용을 이해하는 데 무리가 없도록 구성했다.


ORM의 개념과 기능

데이터베이스를 쉽게 사용할 수 있게 해주는 ORM을 알아보자.
SQLAlchemy ORM 라이브러리를 사용하기로 한다.
ORM 라이브러리를 설치하고 설정 파일을 추가하며, 모델을 만들고 속성을 구상해야 한다.
질문 모델과 답변 모델을 생성하고, 모델을 이용해 테이블을 자동으로 생성해야 한다.
이후 alembic을 설치하고 초기화하여 리비전 파일을 생성하고 실행한다.
마지막으로 생성된 테이블을 살펴보며 DB Browser for SQLite에서 myapi.db 파일을 열어야 한다.


SQL 쿼리와 ORM 비교

SQL 쿼리와 ORM을 비교해 보자.
다음과 같은 형태로 구성된 질문 테이블에 데이터를 입력한다고 가정해 보자.

[question 테이블 구성 예]

idsubjectcontent
1안녕하세요가입 인사드립니다 ^^
2질문 있습니다ORM이 궁금합니다

표에서 id는 각 데이터를 구분하는 고윳값이다.
이렇게 구성된 question 테이블에 새로운 데이터를 삽입하는 쿼리는 보통 다음처럼 작성한다.

[쿼리를 이용한 새 데이터 삽입 예]

insert into question (subject, content) values ('안녕하세요', '가입 인사드립니다 ^^');
insert into question (subject, content) values ('질문 있습니다', 'ORM이 궁금합니다');

하지만 ORM을 사용하면 쿼리 대신 파이썬 코드로 다음처럼 작성할 수 있다.

[ORM을 이용한 새 데이터 삽입 예]

question1 = Question(subject='안녕하세요', content='가입 인사드립니다 ^^')
db.add(question1)
question2 = Question(subject='질문 있습니다', content='ORM이 궁금합니다')
db.add(question2)

ORM을 이용한 새 데이터 삽입 예는 코드 자체만 놓고 보면 양이 많아 보이지만 별도의 SQL 문법을 배우지 않아도 된다는 장점이 있다.
코드에서 Question은 파이썬 클래스이며, 이처럼 데이터를 관리하는 데 사용하는 ORM 클래스를 모델이라고 한다.
모델을 사용하면 내부에서 SQL 쿼리를 자동으로 생성해 주므로 직접 작성하지 않아도 된다.
즉, 파이썬만 알아도 데이터베이스 처리를 할 수 있다.


ORM의 장점

ORM을 이용하면 데이터베이스 종류에 상관없이 일관된 코드를 유지할 수 있어서 프로그램을 유지·보수하기가 편리하다.
또한 내부에서 안전한 SQL 쿼리를 자동으로 생성해 주므로 개발자가 달라도 통일된 쿼리를 작성할 수 있고 오류 발생률도 줄일 수 있다.


SQLAlchemy ORM 라이브러리 사용하기

파이썬 ORM 라이브러리 중 가장 많이 사용하는 SQLAlchemy를 사용해 보자.

ORM 라이브러리 설치하기

다음 명령을 수행하여 SQLAlchemy 라이브러리를 설치하자.

pip install sqlalchemy

설정 파일 추가하기

FastAPI에 ORM을 적용하려면 데이터베이스 설정이 필요하다.
myapi 디렉터리에 database.py 파일을 생성하고 다음과 같은 코드를 작성하자.

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

SQLALCHEMY_DATABASE_URL = "sqlite:///./myapi.db"

engine = create_engine(
    SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

SQLALCHEMY_DATABASE_URL는 데이터베이스 접속 주소이다.
sqlite:///./myapi.db는 sqlite3 데이터베이스의 파일을 의미하며 프로젝트 루트 디렉터리에 저장된다는 의미이다.

그리고 SessionLocal은 데이터베이스에 접속하기 위해 필요한 클래스이다.
create_engine, sessionmaker 등을 사용하는 것은 SQLAlchemy 데이터베이스를 사용하기 위해 따라야 할 규칙이다.
정해진 규칙대로 사용하면 되지만 여기서 autocommit=False 부분은 주의해야 한다.
autocommit=False로 설정하면 데이터를 변경했을 때 commit이라는 사인을 주어야만 실제 저장이 된다.
만약 autocommit=True로 설정할 경우에는 commit이라는 사인이 없어도 즉시 데이터베이스에 변경사항이 적용된다.
그리고 autocommit=False인 경우에는 데이터를 잘못 저장했을 경우 rollback 사인으로 되돌리는 것이 가능하지만 autocommit=True인 경우에는 commit이 필요 없는 것처럼 rollback도 동작하지 않는다는 점에 주의해야 한다.

create_engine은 컨넥션 풀을 생성한다.
컨넥션 풀이란 데이터베이스에 접속하는 객체를 일정 갯수만큼 만들어 놓고 돌려가며 사용하는 것을 말한다.
(컨넥션 풀은 데이터베이스에 접속하는 세션 수를 제어하고, 또 세션 접속에 소요되는 시간을 줄이고자 하는 용도로 사용한다.)
그리고 declarative_base 함수에 의해 반환된 Base 클래스는 데이터베이스 모델을 구성할 때 사용되는 클래스이다.


SQLite는 어떤 데이터베이스일까?

파이썬 기본 패키지에 포함된 SQLite는 주로 소규모 프로젝트에서 사용하는 가벼운 파일을 기반으로 한 데이터베이스이다.
보통은 SQLite로 개발을 빠르게 진행하고 이후 실제 운영 시스템에 반영할 때에는 좀 더 규모가 큰 데이터베이스로 교체한다.


모델 만들기

이제 파이보에서 사용할 모델을 만들어 보자.
파이보는 질문 답변 게시판이므로 질문과 답변에 해당하는 모델이 있어야 한다.

모델 속성 구상하기

질문 모델에는 다음 속성이 필요할 것이다.

[질문 모델 속성]

속성명설명
id질문 데이터의 고유 번호
subject질문 제목
content질문 내용
create_date질문 작성일시

답변 모델은 다음과 같은 속성이 필요하다.

[답변 모델 속성]

속성명설명
id답변 데이터의 고유 번호
question_id질문 데이터의 고유 번호
content답변 내용
create_date답변 작성일시

물론입니다! 아래는 내용을 이어서 정리한 것입니다.


질문 모델 생성하기

이렇게 구상한 속성을 바탕으로 모델을 정의해 보자.
먼저 모델을 정의하기 위한 models.py 파일을 생성하고 질문 모델인 Question 클래스를 다음과 같이 작성해 보자.

[파일명: projects/myapi/models.py]

from sqlalchemy import Column, Integer, String, Text, DateTime
from database import Base

class Question(Base):
    __tablename__ = "question"

    id = Column(Integer, primary_key=True)
    subject = Column(String, nullable=False)
    content = Column(Text, nullable=False)
    create_date = Column(DateTime, nullable=False)

Question과 같은 모델 클래스는 앞서 database.py에서 정의한 Base 클래스를 상속하여 만들어야 한다.
tablename은 모델에 의해 관리되는 테이블의 이름을 뜻한다.
Question 모델은 고유 번호(id), 제목(subject), 내용(content), 작성일시(create_date) 속성으로 구성했으며, 각 속성은 Column으로 생성했다.

Column() 괄호 안의 첫 번째 인수는 데이터 타입을 의미한다.
데이터 타입은 속성에 저장할 데이터의 종류를 결정한다.
Integer는 고유 번호와 같은 숫자값에 사용하고, String은 제목처럼 글자 수가 제한된 텍스트에 사용한다.
글 내용처럼 글자 수를 제한할 수 없는 텍스트는 Text를 사용한다.
작성일시는 날짜 타입인 DateTime을 사용했다.

Column에는 데이터 타입 외에 다음과 같은 속성을 추가로 설정할 수 있다.

primary_key

id 속성에 설정한 primary_keyid 속성을 기본 키(Primary Key)로 만든다.
기본 키는 데이터베이스에서 중복된 값을 가질 수 없게 만드는 설정이다.
id는 모델에서 각 데이터를 구분하는 유일한 값으로 중복되면 안 되므로 기본키로 지정했다.

데이터베이스에서는 id와 같은 특징을 가진 속성을 기본 키(Primary Key)라고 한다.
데이터 타입이 Integer이고 기본키로 설정한 속성은 값이 자동으로 증가하는 특징도 있어서 데이터를 저장할 때 값을 세팅하지 않아도 1씩 자동으로 증가되어 저장된다.

nullable

nullable은 속성에 값을 저장할 때 null 값을 허용할지의 여부이다.
nullable을 따로 설정하지 않으면 해당 속성은 기본으로 null 값을 허용한다.
따라서 속성에 null 값을 허용하지 않으려면 nullable=False로 설정해야 한다.


답변 모델 생성하기

이어서 답변 모델에 해당하는 Answer 클래스를 만들어 보자.

[파일명: projects/myapi/models.py]

from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey
from sqlalchemy.orm import relationship
from database import Base

class Question(Base):
    __tablename__ = "question"

    id = Column(Integer, primary_key=True)
    subject = Column(String, nullable=False)
    content = Column(Text, nullable=False)
    create_date = Column(DateTime, nullable=False)

class Answer(Base):
    __tablename__ = "answer"

    id = Column(Integer, primary_key=True)
    content = Column(Text, nullable=False)
    create_date = Column(DateTime, nullable=False)
    question_id = Column(Integer, ForeignKey("question.id"))
    question = relationship("Question", backref="answers")

답변 모델에서 id, content, create_date 속성은 질문 모델의 id, content, create_date와 의미와 목적이 같다.
다른 속성은 question_idquestion인데 두 속성이 왜 필요하고 어떤 의미를 갖는지 알아보자.

question_id

question_id = Column(Integer, ForeignKey("question.id"))
question_id 속성은 답변을 질문과 연결하기 위해 추가한 속성이다.
답변은 어떤 질문에 대한 답변인지 알아야 하므로 질문의 id 속성이 필요하다.
그리고 모델을 서로 연결할 때에는 위와 같이 ForeignKey를 사용해야 한다.

데이터베이스에서는 기존 모델과 연결된 속성을 외부 키(foreign key)라고 한다.
ForeignKey의 첫 번째 파라미터 'question.id'question 테이블의 id 컬럼을 의미한다.
(질문 객체의 속성 id로 착각하지 말자.)
즉, Answer 모델의 question_id 속성은 question 테이블의 id 컬럼과 연결된다는 뜻이다.

Question 모델을 통해 테이블이 생성되면 테이블명은 question이 된다.

question

question = relationship("Question", backref="answers")
그 다음 question 속성은 답변 모델에서 질문 모델을 참조하기 위해 추가했다.
위와 같이 relationship으로 question 속성을 생성하면 답변 객체(예: answer)에서 연결된 질문의 제목을 answer.question.subject처럼 참조할 수 있다.

relationship의 첫 번째 파라미터는 참조할 모델명이고 두 번째 backref 파라미터는 역참조 설정이다.
역참조란 쉽게 말해 질문에서 답변을 거꾸로 참조하는 것을 의미한다.
한 질문에는 여러 개의 답변이 달릴 수 있는데 역참조는 이 질문에 달린 답변들을 참조할 수 있게 한다.
예를 들어 어떤 질문에 해당하는 객체가 a_question이라면 a_question.answers와 같은 코드로 해당 질문에 달린 답변들을 참조할 수 있다.

SQLAlchemy에서 제공하는 속성은 위에서 소개한 것 외에도 많이 있다.
자세한 내용은 다음의 URL을 참고하자.
SQLAlchemy Documentation

지금까지 설명한 것들을 머리로만 이해하려고 하면 어려울 것이다.
곧이어 실습을 진행할 것이니 대략적인 개념만 숙지하고 넘어가도록 하자.


모델을 이용해 테이블 자동 생성하기

모델을 구상하고 생성했으므로 SQLAlchemyalembic을 이용해 데이터베이스 테이블을 생성해 보자.
alembic은 SQLAlchemy로 작성한 모델을 기반으로 데이터베이스를 쉽게 관리할 수 있게 도와주는 도구이다.
예를 들어 models.py 파일에 작성한 모델을 이용하여 테이블을 생성하고 변경할 수 있다.

alembic 설치하기

다음과 같이 alembic을 설치하자.

pip install alembic

alembic 초기화

alembic이 잘 설치되었다면 이제 alembic 초기화 작업을 진행해야 한다.
파이참 터미널에서 다음과 같은 명령을 실행하자.

alembic init migrations

이 명령을 실행하면 myapi 디렉터리 하위에 migrations라는 디렉터리와 alembic.ini 파일이 생성된다.
migrations 디렉터리는 alembic 도구를 사용할 때 생성되는 리비전 파일들을 저장하는 용도로 사용되고, alembic.ini 파일은 alembic의 환경설정 파일이다.

alembic을 이용하여 테이블을 생성 또는 변경할 때마다 작업 파일이 생성되는데 이 작업 파일을 리비전 파일이라고 한다.
이 리비전 파일은 migrations 디렉터리에 저장된다.

이어서 alembic.ini 파일을 파이참으로 열어서 다음과 같이 수정하자.

[파일명: projects/myapi/alembic.ini]

(... 생략 ...)
sqlalchemy.url = sqlite:///./myapi.db
(... 생략 ...)

alembic이 사용할 데이터베이스의 접속주소를 설정했다.
그리고 migrations 디렉터리의 env.py도 다음과 같이 수정하자.

[파일명: projects/myapi/migrations/env.py]

(... 생략 ...)
import models
(... 생략 ...)
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
target_metadata = models.Base.metadata
(... 생략 ...)

<span

style="color:#1e90ff"> 리비전 파일 생성하기

이제 파이참 터미널에서 alembic revision --autogenerate 명령을 수행하자.

alembic revision --autogenerate

INFO 메시지가 출력되며 리비전 파일이 생성된다.
그러면 migrations/versions 디렉터리에 fed28bf52b05_.py와 같은 리비전 파일이 생성된다.
리비전(revision)이란 생성된 fed28bf52b05_.py 파일에서 .py 확장자를 제외한 fed28bf52b05와 같은 버전 번호를 가리킨다.
리비전은 alembic revision --autogenerate 명령을 수행할 때 무작위로 만들어진다.

리비전 파일에는 테이블을 생성 또는 변경하는 실행문들이 들어 있다.


리비전 파일 실행하기

이어서 alembic upgrade head 명령으로 만들어진 리비전 파일을 실행하자.

alembic upgrade head

이 과정에서 데이터베이스에 모델에 정의한 questionanswer라는 이름의 테이블이 생성된다.
지금까지 잘 따라왔다면 projects/myapi 디렉터리에 myapi.db 파일이 생성되었을 것이다.
myapi.db가 바로 SQLite 데이터베이스의 데이터 파일이다.


alembic 없이 테이블 생성하기

main.py 파일에 다음의 문장을 삽입하면 FastAPI 실행 시 필요한 테이블들이 모두 생성된다.

import models
from database import engine
models.Base.metadata.create_all(bind=engine)

매우 간단한 방법이지만 데이터베이스에 테이블이 존재하지 않을 경우에만 테이블을 생성한다.
한번 생성된 테이블에 대한 변경 관리를 할 수는 없다.
이러한 이유로 이 책에서는 이 방법을 사용하지 않고 alembic을 사용하여 데이터베이스를 관리할 것이다.


생성된 테이블 살펴보기

myapi.db 데이터 파일에 정말로 questionanswer 테이블이 생성되었는지 확인해 보자.
이를 위해 SQLite의 GUI 도구인 DB Browser for SQLite를 사용해 보자.

DB Browser for SQLite 설치하기

DB Browser for SQLite 다운로드 링크 에 접속한 다음 DB Browser for SQLite(이하 DB 브라우저) 설치 파일(standard installer)을 내려받아 설치를 진행하자.
자신의 운영체제에 맞는 설치 파일을 내려받아야 하며, 설치 중 바로 가기(shortcuts)를 생성하는 옵션을 추가해야 쉽게 실행할 수 있다.


DB 브라우저에서 myapi.db 열기

윈도우 바탕화면이나 프로그램 메뉴에서 방금 설치한 DB 브라우저를 실행하고 메뉴에서 [파일 → 데이터베이스 열기]를 선택한다.
그리고 앞선 실습에서 생성한 projects/myapi/myapi.db 데이터베이스 파일을 선택하고 <열기>를 누른다.

테이블 목록을 보면 question, answer 테이블이 생성되었음을 확인할 수 있다.
alembic_version 테이블은 alembic 도구가 데이터베이스를 변경·관리하려고 사용하는 테이블이므로 신경 쓰지 않아도 된다.


아래는 조금 더 상세하게 요약한 내용입니다. 각 항목의 중요 포인트를 포함하면서도 간결하게 정리했습니다.


🏖️ 2-03 모델로 데이터 처리하기

이전 장에서는 질문과 답변 모델을 생성하고 테이블을 만들었다. 이 모델을 사용하여 데이터를 생성, 수정, 삭제, 조회하는 방법에 대해 알아보겠다.


데이터 처리 방법

1. 파이썬 셸 실행하기

작성한 모델을 테스트하기 위해 파이썬 셸을 사용하는 것이 가장 좋은 방법이다.
파이참 터미널에서 "python"이라고 입력하여 파이썬 셸을 실행하자.
셸을 실행하기 전에 myapi 가상환경에 접속해 있는지 확인해야 하며, 터미널 프롬프트에 (myapi)라는 문구가 표시되어 있어야 한다.
이 표시가 없으면 myapi를 입력하여 가상환경에 접속하자.

(myapi) myapi % python
Python 3.10.0 (v3.10.0:b494f5935c, Oct  4 2021, 14:59:20) [Clang 12.0.5 (clang-1205.0.22.11)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 

2. 질문 저장하기

Question 모델 객체를 생성한 후 데이터베이스에 저장하는 과정은 다음과 같다.

>>> from models import Question
>>> from database import SessionLocal
>>> db = SessionLocal()
>>> q = Question(subject='pybo가 무엇인가요?', content='pybo에 대해서 알고 싶습니다.', create_date=datetime.now())
  
>>> from database import SessionLocal
>>> db = SessionLocal()
>>> db.add(q)
>>> db.commit()

이 과정을 통해 q 객체가 데이터베이스에 저장되며, id 속성을 통해 저장된 데이터를 확인할 수 있다.

>>> q.id  # 1
>>> q = Question(subject='FastAPI 모델 질문입니다.', content='id는 자동으로 생성되나요?', create_date=datetime.now())
>>> db.add(q)
>>> db.commit()
>>> q.id
2

3. 커밋(commit)과 롤백(rollback)

커밋은 작업을 확정하는 과정이므로, 일단 커밋을 하면 취소할 수 없다.
작업을 취소하려면 커밋 이전에 진행해야 하며, db.rollback()을 통해 롤백을 실행하면 이전 상태로 되돌릴 수 있다.


4. 데이터 조회하기

데이터베이스에 저장된 데이터를 조회하는 방법은 다음과 같다.

>>> db.query(Question).all()  # 모든 질문 조회
>>> db.query(Question).filter(Question.id==1).all()  # 특정 id의 질문 조회

특정 문자열이 포함된 질문을 조회할 때는 like 함수를 사용하여 유연하게 검색할 수 있다.

>>> db.query(Question).filter(Question.subject.like('%FastAPI%')).all()  # "FastAPI" 포함

이 때 % 기호는 문자열의 시작, 끝, 포함 여부를 표시하는데 사용된다.


5. 데이터 수정하기

질문 데이터를 수정할 때는 대입 연산자를 사용하면 된다.

>>> q = db.query(Question).get(2)  # id가 2인 질문 조회
>>> q.subject = 'FastAPI Model Question'  # subject 수정
>>> db.commit()  # 커밋하여 변경사항 반영

수정 후에는 반드시 커밋을 통해 변경사항을 데이터베이스에 반영해야 한다.


6. 데이터 삭제하기

데이터를 삭제하는 방법은 다음과 같다.

>>> q = db.query(Question).get(1)  # id가 1인 질문 조회
>>> db.delete(q)  # 삭제
>>> db.commit()  # 커밋하여 변경사항 반영

삭제 후 데이터베이스에서 삭제가 잘 이루어졌는지 확인할 수 있다.


7. 답변 데이터 저장하기

답변(Answer)을 생성하고 저장하는 과정은 다음과 같다.

>>> from models import Answer
>>> q = db.query(Question).get(2)  # 연결할 질문 조회
>>> a = Answer(question=q, content='네 자동으로 생성됩니다.', create_date=datetime.now())
>>> db.add(a)  # 답변 추가
>>> db.commit()  # 커밋하여 저장

답변 객체를 생성할 때 question 속성에 질문 객체를 대입하여 연결한다.
Answer 모델의 id 속성도 기본 키이므로 자동으로 생성된다.


8. 질문과 답변 관계

Answer 모델의 question 속성을 사용하면 답변에 연결된 질문을 조회할 수 있다.

>>> a.question  # 답변에 연결된 질문 조회

역으로, 질문에 연결된 답변을 조회하는 것도 가능하다.
질문 모델에 설정된 backref를 통해 연결된 답변들을 쉽게 가져올 수 있다.

>>> q.answers  # 질문에 달린 답변 조회

종료하기

파이썬 셸에서 나가려면 <Ctrl+Z>를 누르고 를 입력하거나 quit()를 입력하면 된다.


profile
AI Engineer / 의료인공지능

0개의 댓글