본문 바로가기

Python

Flask 4 : DB 구축

2019년 여름 현재 시중에 나와있는 Flask 책은 추천하기에 마땅치 않아, Flask 공식 웹사이트에서 제공하는 튜토리얼로 공부하시기를 권해드립니다. 하지만, 공식 웹사이트는 영어라는거...

그래서 Flask 공식 웹사이트 튜토리얼에 대한 번역을 올립니다. 원문의 흐름에 따라 번역했고, 이해를 돕기 위해 직역보다는 의역을 합니다.

원문 : https://flask.palletsprojects.com/en/1.1.x/tutorial/


DB 구축

사용자 데이터와 블로그 글 데이터를 저장하기 위해 SQLite 라는 데이터베이스를 이용합니다. SQLite는 파이썬 빌트인 데이터베이스로 sqlite3 모듈을 이용해 접근하게 됩니다.

SQLite는 파이썬 빌트인 데이터베이스라 별도로 설정을 할 필요가 없어 편리합니다. 하지만 동시에 다중 write가 안된다는 단점이 있습니다. 작은 테스트 사이트에서는 문제가 없지만, 상용으로 사용할 것이라면 다른 데이터베이스를 선택하는 것이 유용할 수 있습니다.

튜토리얼에스는 SQL 문법은 자세히 다루지 않습니다.

데이터베이스 연결

데이터베이스를 사용하기 위해 첫 번째 할 일은 앱과 데이터베이스를 연결해주는 일 입니다. 이후 데이터베이스로의 모든 쿼리는 이 커넥션을 통해 전달되고, 수행이 완료되면 커넥션을 닫아줍니다.

웹 어플리케이션은 통상적으로 request를 통해 커넥션을 연결시키고, response를 보내기 직전에 닫아줍니다.
flaskr/db.py
import sqlite3

import click
from flask import current_app, g
from flask.cli import with_appcontext


def get_db():
    if 'db' not in g:
        g.db = sqlite3.connect(
            current_app.config['DATABASE'],
            detect_types=sqlite3.PARSE_DECLTYPES
        )
        g.db.row_factory = sqlite3.Row

    return g.db


def close_db(e=None):
    db = g.pop('db', None)

    if db is not None:
        db.close()

g 는 각각의 request 에 할당되는 고유한 객체 인데요, request에 해당하는 데이터를 저장하는데 사용됩니다. get_db 함수는 최초 실행시 g 객체를 생성해서 할당해주는데, 두 번째 실행 부터는 새로 g 객체를 생성하지 않고 이미 생성해놓은 g를 재활용 합니다.

current_app 은 request를 발생시킨 Flask 앱을 가리키는 객체 입니다. 여기에서는 어플리케이션 팩토리를 이용하기 때문에, 더이상 새로운 객채를 만들 필요는 없습니다. get_db에서 이미 생성한 객체, 즉 current_app을 사용합니다.

sqlite3.connect() 는 데이터베이스 설정 키값에서 지정한 파일로 커넥션을 맺어줍니다. 아직 이 파일이 있을 필요는 없구요, 뒤에서 초기화를 시켜줄 때 생성됩니다.

sqlite3.Row 는 커넥션이 결과값을 딕셔너리 형태로 돌려주게 합니다. 이를 통해 각 컬럼에 컬럼명을 이용해 접근할 수 있습니다.

close_db g 객체의 db 값을 확인해서 커넥션이 생성되었는지 확인하고, 커넥션이 생성되었으면 닫아줍니다. 


테이블 생성

SQLite는 데이터를 테이블과 컬럼 형태로 저장합니다. 테이블과 컬럼은 데이터를 저장하고 조회하기에 앞서 미리 만들어져야 합니다. Flasr는 사용자 관련 데이터를 user 테이블에, 게시물 관련 데이터를 post 테이블에 저장합니다. 이제 SQL 명령어를 이용해서 빈 테이블을 저장할 파일을 만들어봅니다:

flaskr/schema.sql
DROP TABLE IF EXISTS user;
DROP TABLE IF EXISTS post;

CREATE TABLE user (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  username TEXT UNIQUE NOT NULL,
  password TEXT NOT NULL
);

CREATE TABLE post (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  author_id INTEGER NOT NULL,
  created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  title TEXT NOT NULL,
  body TEXT NOT NULL,
  FOREIGN KEY (author_id) REFERENCES user (id)
);


이제 SQL 명령어를 실행시킬 파이썬 함수를 추가합니다. 파일명은 db.py 입니다:

flaskr/db.py
def init_db():
    db = get_db()

    with current_app.open_resource('schema.sql') as f:
        db.executescript(f.read().decode('utf8'))


@click.command('init-db')
@with_appcontext
def init_db_command():
    """Clear the existing data and create new tables."""
    init_db()
    click.echo('Initialized the database.')

open_resource() opens a file relative to the flaskr package, which is useful since you won’t necessarily know where that location is when deploying the application later. get_db returns a database connection, which is used to execute the commands read from the file.

get_db를 통해 데이터베이스 커넥션을 맺고, open_resource() 로 상대위치에서 지정한 파일을 가져옵니다.  그리고 이 파일에서 읽어온 명령어는 커넥션을 통해 실행합니다.

click.command() 는 db를 초기화하는 init_db 기능을 수행하고, 성공 여부를 반환합니다.

어플리케이션에 등록

close_db와 init_db_command 기능을 앱 인스턴스로 등록해야 앱에서 사용할 수 있습니다. 여기에서는 팩토리를 사용하기 때문에 인스턴스는 함수 작성 시 생성되지는 않구요, 등록을 하는 앱을 통해 생성됩니다.
flaskr/db.py
def init_app(app):
    app.teardown_appcontext(close_db)
    app.cli.add_command(init_db_command)

app.teardown_appcontext() 은 response를 돌려주고 나서 close_db를 실행시킵니다.

app.cli.add_command() 는 flask 커맨드와 함께 수행될 함수를 추가합니다.

팩토리에서 이 기능을 임포트해서 실행합니다. 관련 코드는 앱 반환 앞에 추가해줍니다.

flaskr/__init__.py

def create_app(): app = ... # 기존 코드는 생략 from . import db db.init_app(app) return app


데이터베이스 파일 초기화

init-db 기능이 앱에 등록되었다면, flask 명령어를 통해 실행시킬 수 있습니다. 

Note

앞 페이지에서 실행시켜놓은 웹서버가 여전히 가동 중이라면, flask init-db를 실행시키기 위해 가동중인 서버를 중지시킨 후 flask init-db를 실행시킬 수 있습니다. 

이제 init-db 명령을 실행시킵니다:

$ flask init-db
Initialized the database.

이제 프로젝트 폴더에 instance 폴더가 생성되고, 폴더 내에 flaskr.sqlite 파일이 만들어졌을 것입니다.

다음 : 블루프린트와 뷰.


'Python' 카테고리의 다른 글

Flask 6 : 템플릿  (0) 2019.09.06
Flask 5 : 블루프린트와 뷰  (0) 2019.08.28
Flask 3 : 어플리케이션 설치  (0) 2019.08.28
Flask 2 : 프로젝트 구조  (0) 2019.08.28
Flask 1 : Tutorial 소개  (1) 2019.08.27