[LG U+ 5기]/Study

[4월][1주차] 플라스크 개발 (1) - ORM

jjanggun0930 2025. 4. 4. 13:59

2025.04.01

 

[ORM 이란?]

더보기

ORM이란?

ORM (Object-Relational Mapping)
👉 객체 지향 언어(Python, Java 등)의 객체
👉 데이터베이스의 테이블과 매핑해주는 기술


쉽게 말하면?

# sql
SELECT * FROM users WHERE id = 1;

 

ORM을 쓰면, 이렇게 Python 코드로 가능

 
# python
user = User.query.get(1)

ORM의 핵심 역할

  • 클래스 ↔️ 테이블 매핑
  • 인스턴스(객체) ↔️ 레코드(행) 매핑
  • SQL 직접 안 쓰고도 데이터를 조회/삽입/수정/삭제 가능

ORM의 장점

  • 가독성 좋아짐 (SQL 몰라도 기본적인 조작 가능)
  • 코드 재사용성
  • 데이터 조작 시 코드 스타일 통일
  • 다양한 DB에 대한 추상화 (MySQL → SQLite 등 전환 쉬움)

단점

  • 복잡한 쿼리는 직접 SQL 쓰는 게 더 나을 수도 있음
  • 성능이 중요한 대용량 시스템에서는 ORM이 느릴 수 있음

정리하자면:

ORM은 객체지향 프로그래밍과 관계형 데이터베이스를 연결해주는 다리 역할을 하는 도구

1. ORM 라이브러리 설치 

  • 가상 환경 들어가기 
C:> myproject
(myproject) c:\projects\myproject>pip install flask-migrate

 

2. 설정 파일 추가

[파일명 : "C:\projects\myproject\config.py"]

py 파일 생성

파이썬 idle 에서 config 열기

더보기

방법 1 ) 원래 위에 py 파일을 마우스 오른쪽 버튼 누르고 → 연결 프로그램에서 파이썬 선택하면 열려야 하는데..

* 내꺼는 바로 안뜸..^^

 

방법 2 ) 윈도우 탐색기에서  직접 열어서 파일 open 으로 불러오기

파이썬 IDLE

파이썬 idle 에서 config 열기

 

  • 데이터베이스 접속 주소 : SQLALCHEMY_DATABASE_URI = 'sqlite:///{ }'.format( os.path.join(BASE_DIR,'pybo.db')
  • SQLALchemy의 이벤트를 처리하는 옵션 : SQLALCHEMY_TRACK_MODIFICATIONS = False 
    • False : 파이보에는 필요하지 않은 옵션이라서 비활성화

IDLE 에다가 이렇게 코드 작성하면 된다.

하나하나 코드 쓰려니까 좀 힘들군..

3. ORM 적용

어제 사용한 __init__.py 사용 !

 

[파일명 : "C:\projects\myproject\pybo\__init__.py"]

 

원래 있던 코드에서 수정 및 추가

[코드 설명]

더보기
# Flask 앱 생성 및 초기 설정 관련 모듈
from flask import Flask

# SQLAlchemy: ORM 기능 제공
from flask_sqlalchemy import SQLAlchemy

# Flask-Migrate: 데이터베이스 마이그레이션(스키마 변경 관리)
from flask_migrate import Migrate

# 설정값을 담은 별도 파일(config.py) 불러오기
import config

# SQLAlchemy 객체와 Migrate 객체 생성 (아직 앱과 연결하지 않음)
db = SQLAlchemy()
migrate = Migrate()


def create_app():
    # Flask 앱 인스턴스 생성
    app = Flask(__name__)

    # config.py의 설정값(app.config['SQLALCHEMY_DATABASE_URI'] 등)을 앱에 적용
    app.config.from_object(config)

    # SQLAlchemy 객체를 Flask 앱에 연결 → ORM 기능 활성화
    db.init_app(app)

    # Flask-Migrate를 앱과 db에 연결 → DB 구조 변경을 자동으로 추적할 수 있게 됨
    migrate.init_app(app, db)

    # views 디렉토리 안의 main_views 모듈에서 블루프린트(bp) 불러오기
    from .views import main_views

    # 블루프린트를 앱에 등록 → URL 라우팅 기능 활성화
    app.register_blueprint(main_views.bp)

    # 최종적으로 설정 완료된 Flask 앱 객체 반환
    return app

전체 구조 이해 포인트

  • SQLAlchemy(): 파이썬 클래스를 DB 테이블로 연결해주는 ORM 도구
  • Migrate(): DB 구조 변경사항을 쉽게 관리해주는 도구 (flask db migrate, upgrade 등)
  • create_app(): 앱 실행 시 호출되는 함수로, Flask에서 권장하는 앱 팩토리 패턴 사용
  • Blueprint: 다양한 라우팅 파일을 구조적으로 분리 관리하기 위한 기능

저장하고 

4. 데이터베이스 초기화

(myproject) c:\projects\myproject>flask db init

마이그레이션 파일 생성 !

  • flask db init 명령은 데이터베이스를 관리하는 초기 파일들을 다음처럼 migrations 디렉터리에 자동으로 생성한다.
  • 데이터베이스를 초기화하는 flask db init 명령은 최초 한 번만 수행

5. 데이터베이스 관리 명령어 정리

모델을 추가하거나 변경할 때,

> flask db migrate 
> flask db upgrade
flask db migrate 모델을 새로 생성하거나 변경할 때 사용
(실행하면 작업파일이 생성된다.)
flask db upgrade 모델의 변경 내용을 실제 데이터베이스에 적용할 때 사용
(위에서 생성된 작업파일을 실행하여 데이터베이스를 변경한다.)

 

6. 질문/답변 모델 생성

  • pybo 폴더 안에 → .py 파일 생성

models.py 파일에는 모델 클래스들을 정의하여 사용

 

[파일명: projects/myproject/pybo/models.py]

모델.py 파일 생성

  • models.py 파일 열어서 질문/ 답변 모델 생성 코드 짜기 
더보기
# models.py - ORM 모델 정의 파일
from pybo import db  # SQLAlchemy 인스턴스 가져오기

# 질문 테이블 정의
class Question(db.Model):
    # 고유 ID (기본 키)
    id = db.Column(db.Integer, primary_key=True)

    # 질문 제목 (최대 200자, 필수 입력)
    subject = db.Column(db.String(200), nullable=False)

    # 질문 내용 (길이 제한 없음, 필수 입력)
    content = db.Column(db.Text(), nullable=False)

    # 질문 생성 날짜 (필수 입력)
    create_date = db.Column(db.DateTime(), nullable=False)


# 답변 테이블 정의
class Answer(db.Model):
    # 고유 ID (기본 키)
    id = db.Column(db.Integer, primary_key=True)

    # 외래 키: 어떤 질문에 대한 답변인지 지정
    question_id = db.Column(
        db.Integer,
        db.ForeignKey('question.id', ondelete='CASCADE'))  # 질문 삭제 시 연결된 답변도 삭제

    # 관계 설정: Answer → Question
    # answer.question 으로 연결된 질문 객체 접근 가능
    # question.answer_set 으로 해당 질문에 달린 답변 목록 접근 가능
    question = db.relationship('Question', backref=db.backref('answer_set'))

    # 답변 내용 (필수 입력)
    content = db.Column(db.Text(), nullable=False)

    # 답변 생성 날짜 (필수 입력)
    create_date = db.Column(db.DateTime(), nullable=False)

 

models.py에는 질문(Question)과 답변(Answer)을 위한 ORM 모델이 정의되어 있으며,

두 모델은 1:N 관계로 연결되어 있음

ondelete = 'CASCADE' 쿼리를 이용하여 질문 데이터를 삭제할 경우 답변도 함께 삭제된다. 

파이썬 코드로 질문 데이터를 삭제하면
해당 질문과 연결된 답변 데이터는 삭제되지 않고
답변 데이터의 question_id 컬럼만 빈값으로 업데이트

파이썬 코드로 질문 데이터를 삭제할 때
연결된 답변 모두를 삭제하려면, 
db.backref 설정에 cascade = 'all, delete-orphan'

7. 모델 import

아까 init 파일에서 orm 또 수정 

[파일명: projects/myproject/pybo/__init__.py]

8. 리비전 파일 생성

(myproject) c:\projects\myproject>flask db migrate

 

하면 마이그레이션 폴더 -> 버젼 폴더 -> 임의의 숫자.py 파일 생성

9. 리비전 파일 실행

(myproject) c:\projects\myproject>flask db upgrade

 

10. DB 브라우저에서 pybo.db 열기

설치한 DB 브라우저를 실행

SQLite 화면

 

메뉴에서 [파일 → 데이터베이스 열기]를 선택.

그리고 앞선 실습에서 생성한 projects/myproject/pybo.db 데이터베이스 파일을 선택하고 <열기>를 누르기

데이터베이스 열기에서 pybo.py 파일 선택
아까 models.py 에서 만든대로 answer / question 들어간 것 확인
쿼리 실행은 셀렉트하고 ctrl + enter

11. 플라스크 셸 실행하기

(myproject) c:\projects\myproject>flask shell

12. 질문 저장하기

# 1. Question, Answer 모델 불러오기
>>> from pybo.models import Question, Answer

# 2. 현재 시각을 저장하기 위해 datetime 모듈 사용
>>> from datetime import datetime

# 3. Question 클래스 인스턴스 생성
#    아직 DB에 저장된 건 아니고, 메모리에만 존재하는 상태
>>> q = Question(
    	subject='pybo가 무엇인가요?',                     # 질문 제목
    	content='pybo에 대해서 알고 싶습니다.',           # 질문 내용
    	create_date=datetime.now())                       # 생성 시각

# 4. SQLAlchemy의 db 객체 불러오기 (세션을 통해 DB 조작 가능)
>>> from pybo import db

# 5. 위에서 만든 질문 객체를 DB 세션에 추가 (등록만 해두는 상태)
>>> db.session.add(q)

# 6. 세션의 변경사항을 커밋 → 실제로 DB에 저장됨
>>> db.session.commit()

commit 한 데이터가 보인다 !

 

+ 추가 질문

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

추가 완 !

13. 데이터 수정

  • 수정할 때는 단순히 대입 연산자 사용
>>> q = Question.query.get(2)
>>> q
<Question 2>
>>> q.subject = 'Flask Model Question'
>>> db.session.commit()

14. 데이터 삭제

  • delete 함수를 이용해 삭제
>>> q = Question.query.get(1)
>>> db.session.delete(q)
>>> db.session.commit()

15. 답변 데이터 저장

>>> from datetime import datetime
>>> from pybo.models import Question, Answer
>>> from pybo import db
>>> q = Question.query.get(2)
>>> a = Answer(question=q, content='네 자동으로 생성됩니다.', create_date=datetime.now())
>>> db.session.add(a)
>>> db.session.commit()

답변 데이터도 넣고 ~

16. 답변에 연결된 질문 찾기

  • Answer 모델의 question 속성을 이용하면 "답변에 연결된 질문"을 조회할 수 있다.
>>> a.question
<Question 2>

17. 질문에 달린 답변 찾기

  • answer_set 을 사용하면 질문에 연결된 답변들을 쉽게 가져올 수 있다.
>>> q.answer_set
[<Answer 1>]

 

18. 플라스크 셸 종료

  • 플라스크 셸에서 빠져 나오려면 <Ctrl+Z>를 누르고 <Enter>를 입력한다. 또는 quit()를 입력한다.