Flask는 기본적으로 데이터베이스를 지원하지 않습니다. 사용자가 원하는 DB를 선택할 수 있습니다.

 

 

 

1. Flask-SQLAlchemy 설치

실습을 위해 Flask-SQLAlchemy를 설치하겠습니다.

$ pip install flask-sqlalchemy

 

 

 

2. Flask-migrate 설치

DB 사용에 대해서는 쉽게 정보를 얻을 수 있지만, 응용 프로그램 변경 혹은 증가에 따른 DB업데이트 문제를 잘 다루지 않습니다. 우리는 구조가 변경되는 등의 상황을 대비한 migrate 확장자까지 설치하겠습니다.

$ pip install flask-migrate

 

 

 

3. Flask-SQLAlchemy 구성

# config.py
import os

basedir = os.path.abspath(os.path.dirname(__file__))

class Config(object):
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'you-will-never-guess'
    # 응용프로그램 데이터베이스의 위치를 가져옴, DATABASE_URL 환경 변수에서 데이터베이스 URL을 가져오고, 정의되지 않은 경우 변수에 저장된 응용 프로그램의 기본 디렉토리에 app.db라는 데이터베이스를 구성하고 있다.
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
        'sqlite:///' + os.path.join(basedir, 'app.db')
    SQLALCHEMY_TRACK_MODIFICATIONS = False

 

 

 

4. Flask-SQLAlchemy 및 Flask-Migrate 초기화

# app/__init__.py
from flask import Flask
from config import Config
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
migrate = Migrate(app, db)

# routes와 데이터베이스 구조 정의하는 models 호출
from app import routes, models

 

 

 

5. 사용자에 대한 DB 모델

# vim app/models.py
from app import db

class User(db.Model):
    idx = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), index=True, unique=True)
    email = db.Column(db.String(120), index=True, unique=True)
    password_hash = db.Column(db.String(128))

    # 클래스의 객체를 print하는 방법
    def __repr__(self):
        return '<User {}>'.format(self.username)
# TEST
from app.models import User
u = User(username='susan', email='susan@example.com')
print(u)
# 출력값 : <User susan>

 

 

 

6. Micro blog용 마이그레이션 저장소 작성

$ flask db init

 

 

 

7. 마이그레이션 생성

$ flask db migrate -m "users table"

 

 

 

8. db 업그레이드

위의 flask db migrate 명령어는 데이터베이스를 변경하지 않고 마이그레이션 스크립트만 생성합니다. 데이터베이스에 변경 사항을 적용하기 위해서는 아래 명령어를 사용해야 합니다.

$ flask db upgrade

이 응용 프로그램은 SQLite를 사용하기 때문에, 데이터베이스가 존재하지 않음을 감지하고 새로 작성합니다. 이 명령어 완료 후 app.db라는 파일이 추가됩니다. (SQLite데이터베이스)

Mysql이나 PostgreSQL과 같은 데이터베이스 서버로 작업하는 경우 싱행하기 전에 DB 서버에서 DB를 작성해야합니다.

 

 

 

9. 정리

데이터베이스 마이그레이션 지원을 사용하면 애플리케이션에서 모델을 수정한 후 새 마이그레이션 스크립트 ( flask db migrate) 를 생성한 후 자동 생성이 올바르게 수행되었는지 확인한 후 변경사항을 개발 데이터베이스 ( flask db upgrade)에 적용할 수 있습니다 . 마이그레이션 스크립트를 소스 제어에 추가하고 커미트합니다.

새 버전의 애플리케이션을 프로덕션 서버에 릴리스 할 준비가되면 업데이트 된 애플리케이션 버전 (새 마이그레이션 스크립트 포함)을 가져 와서 실행하면 flask db upgrade됩니다.

flask db downgrade 명령어를 통해 마지막 마이그레이션을 실행 취소할 수 있습니다 . 프로덕션 시스템에서이 옵션이 필요하지는 않지만 개발 중에 매우 유용 할 수 있습니다.

 

 

 

10. 데이터베이스 테이블 및 관계 게시 - 게시글 부문 추가

# vim app/models.py
from app import db
from datetime import datetime

class User(db.Model):
    idx = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), index=True, unique=True)
    email = db.Column(db.String(120), index=True, unique=True)
    password_hash = db.Column(db.String(128))

    def __repr__(self):
        return '<User {}>'.format(self.username)

class Post(db.Model):
    idx = db.Column(db.Integer, primary_key=True)
    body = db.Column(db.String(140))
    timestamp = db.Column(db.DateTime, index=True, default=datetime.now)
    user_idx = db.Column(db.Integer, db.ForeignKey('user.idx'))

    def __repr__(self):
        return '<Post {}>'.format(self.body)

Post의 user_id는 외래키인 user.idx 값을 가져오는 설정으로 해줍니다.

 

 

 

11. 데이터베이스 마이그레이션

어플리케이션 모델에 대한 업데이트가 있으므로, 새 데이터베이스 마이그레이션을 생성한 후 DB에 적용해야합니다.

소스 제어에 프로젝트를 저장하는 경우 새 마이그레이션 스크립트를 추가해야합니다.

$ flask db migrate -m "posts table"

$ flask db upgrade

 

 

 

12. 데이터베이스에 데이터 넣어보기

from app import db
from app.models import User, Post

u = User(username='john', email='john@example.com')
db.session.add(u) 
db.session.commit() 
u = User(username='susan', email='susan@example.com') 
db.session.add(u) 
db.session.commit() 
users = User.query.all() 
print(users)
# [<User john>, <User susan>]

for u in users:
    print(u.idx, u.username, u.email)
# 1 john john@example.com
# 2 susan susan@example.com

 

 

 

13. 블로그에 게시물 추가하기

from app import db
from app.models import User, Post
u = User.query.get(1)
print(u)
p = Post(body='my first post!', user_idx=1)
db.session.add(p)
db.session.commit()

timestamp 필드에는 모델 정의에서 기본값이 정해져있기 때문에 필드 값을 따로 설정할 필요가 없다.

 

 

 

14. DB 삭제하고 다시 만들기 실습

DB가 잘못된 경우, 혹은 다시 만들고 싶은 경우 아래와 같이 진행하면 됩니다. 한번 다 삭제하고 다시 만들어봅니다.

$ rm -rf app.db

$ rm -rf migrations

다시 만들면서 models.py 를 조금 수정하겠습니다. idx였던 부분들을 id로 변경하겠습니다. 꼭 진행해주세요.

# vim app/models.py

from app import db
from datetime import datetime

class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), index=True, unique=True)
    email = db.Column(db.String(120), index=True, unique=True)
    password_hash = db.Column(db.String(128))
    # 클래스의 객체를 print하는 방법
    def __repr__(self):
        return '<User {}>'.format(self.username)

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    body = db.Column(db.String(140))
    timestamp = db.Column(db.DateTime, index=True, default=datetime.now)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    # 클래스의 객체를 print하는 방법
    def __repr__(self):
        return '<Post {}>'.format(self.body)

$ flask db init

$ flask db migrate -m "users, posts making again!"

$ flask db upgrade

 

 

 

15. 가상의 필드를 사용하여 게시물에 작성자를 할당

# vim app/models.py

from app import db
from datetime import datetime

class User(UserMixin, db.Model):
    # ...
    # 가상 필드 author를 만들어줌, posts 사용자에게 속성 추가
    posts = db.relationship('Post', backref='author', lazy='dynamic')
    # 클래스의 객체를 print하는 방법
    def __repr__(self):
        return '<User {}>'.format(self.username)

# ...
# python 명령 프롬프트
from app import db
from app.models import User, Post

u = User.query.get(1)
print(u)
# 출력값 : <User susan>

p = Post(body='my first post!', author=u)
db.session.add(p)
db.session.commit()
u.posts.all()
# 출력값 : [<Post my first post!>]

posts = Post.query.all()
for p in posts:
    print(p.id, p.author.username, p.body)
# 출력값 : 1 susan my first post!

User.query.order_by(User.username.desc()).all()
# 출력값 : [<User susan>]

 

 

 

16. 기본적인 데이터베이스 쿼리 확인해보기

# get all posts written by a user
u = User.query.get(1)
u
# 출력값 : <User john>

posts = u.posts.all()
posts
# 출력값 : [<Post my first post!>]

# same, but with a user that has no posts
u = User.query.get(2)
u
# 출력값 : <User susan>

u.posts.all()
# 출력값 : []

# print post author and body for all posts 
posts = Post.query.all()
for p in posts:
    print(p.id, p.author.username, p.body)
# 출력값 : 1 john my first post!

# get all users in reverse alphabetical order
User.query.order_by(User.username.desc()).all()
# 출력값 : [<User susan>, <User john>]

더 많은 Flask-SQLAlchemy에 대한 정보는 아래 링크를 통해 확인할 수 있습니다. 좋은 예시들이 많습니다.

https://flask-sqlalchemy.palletsprojects.com/en/2.x/

 

 

+ Recent posts