플라스크로 나만의 웹 페이지 만들기-05
Intro
이 포스트는 플라스크로 나만의 웹 페이지 만들기 - 04 에 의존합니다. 이전 포스트를 먼저 보시는걸 추천합니다.
SQL 데이터베이스
데이터베이스는 구조적인 방법으로 애플리케이션 데이터를 저장한다. 애플리케이션은 필요한 특정 데이터를 추출하기 위해 쿼리(query)
를 실행한다.
사실 SQL이라는 이름도 구조화된 쿼리 언어(Structured Query Language)이다.
또, 최근에는 문서기반(document-oriented)과 키-값(key-value) 데이터베이스를 사용하기 시작했는데 이러한 데이터베이스는 NoSQL
데이터베이스로 대중화되고 있다.
관계형 데이터베이스에는 테이블(Table)
에 데이터를 저장하며 애플리키이션 도메인에 따라 다른 엔터티를 모델링한다. 예를들어 주문 관리 애플리케이션을 위한 데이터베이스는 customers, products, orders 같은 테이블을 갖게 되는식.
테이블은 고정된 수의 열(Column)
과 변경 가능한 수의 행(Row)
으로 구성된다. 기본 개념과 명령어는 생활코딩 동영상을 참고하자.
파이썬 데이터베이스 프레임워크
파이썬은 오픈 소스와 상용 데이터베이스에 대한 대부분의 데이터베이스 엔진을 위한 패키지를 갖고 있다. 이 말은 곧 사용자가 어떤 DB를 사용하든 제한이 없다는 이야기. 원한다면 MySQL, Postgre, SQLite, Redis, MongoDB, CouchDB등 편한것을 사용하면 된다.
선택하기 쉽지않다면 SQLAlchemy
나 MongoEngine
같은 데이터베이스 추상화 레이어를 사용해보자. 이건 쿼리언어같은 기본 데이터베이스 엔터티 대신 일반적인 파이썬 오브젝트보다 더 상위 레벨에서 동작 할 수 있도록 한다.
우리는 Flask-SQLAlchemy를 사용한다. 한글발음은 플라스크 에스큐엘 알케미…정도?
기존의 DB를 다루는 방법중에서 객체지향적 사고방식을 접목한 것으로 모델(class) 들의 개념과 관계형 데이터베이스에 속하는 MySQL의 관계(Relation)를 따로따로 보지 않고 연결해서 보는게 특징이다.
Flask-SQLAlchemy
대부분의 확장과 마찬가지로 pip
를 사용하여 설치한다.
$ pip install flask-sqlalchemy
Flask-SQLAlchemy에서 데이터베이스는 URL을 사용하여
설정한다. 아래의 표는 가장 인기 있는 세 개의 데이터베이스 엔진을 위한 데이터베이스 URL 포맷 리스트다.
데이터베이스 엔진 | URL |
---|---|
MySQL | mysql://username:password@hostname/database |
Postgre | pstgresql://username:password@hostname/database |
SQLite(리눅스) | sqlite:////absolute/path/to/database |
SQLite(윈도우) | sqlite:///c:/absolute/path/to/database |
이 URL에서 hostname
은 MySQL 서비스를 호스트하는 서버를 참조하는데 로컬호스트(localhost)
나 리모트 서버가 될 수 있다. 데이터베이스 서버는 여러 데이터베이스를 호스트하므로 database
는 사용할 데이터베이스 이름을 가리킨다. 인증을 위해 데이터베이스에 username
과 password
를 데이터베이스 사용자 자격으로 사용한다. SQLite 데이터베이스는 서버를 갖고있지 않으므로 hostname과 username, password가 생략되고 database는 디스크 파일에 있는 파일 이름을 사용한다.
애플리케이션 데이터 베이스의 URL은 플라스크 설정 오브젝트에서 SQLALCHEMY_DATABASE_URI
키로 설정되어야 한다. 다른 사용자 옵션은 설정키인 SQLALCHEMY_COMMIT_ON_TEARDOWN
인데, 이 키는 True로 설정하면 각 리퀘스트의 끝에 데이터베이스 변경사항을 자동 커밋한다.
아래 예제로 SQLite 데이터베이스를 초기화하고 설정하는 방법을 보여준다.
1
2
3
4
5
6
7
8
9
10
from flask.ext.sqlalchemy import SQLAlchemy
basedir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] =\
'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app. config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
db = SQLAlchemy(app)
클래스 SQLAlchemy에서 인스턴스화된 db 오브젝트는 데이터베이스를 표현하고 Flask-SQLAlchemy에 대한 모든 기능을 액세스할 수 있도록 해준다.
모델
모델(model)
이라는 용어는 애플리케이션에서 사용되는 영구적인 엔터티를 참조할때 사용한다. ORM의 컨텍스트 에서는 일반적으로 데이터베이스 테이블의 열과 매칭되는 속성을 갖는다.
다음 예제는 Role과 User모델을 정의한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
def __repr__(self):
return '<Role %r>' % self.name
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Colum(db.String(64), unique=True, index=True)
def __repr__(self):
return '<User %r>' % self.username
__tablename__ 클래스 변수는 데이터베이스에 있는 테이블 이름을 정의하는데 만약 생략되었다면 디폴트 테이블 이름을 할당한다. 테이블 이름을 명확하게 설정하자.
db.Column
생성자에 넘겨진 첫 번째 인수는 데이터베이스 열의 타입이며 모델 속성이다. 일반적인 데이터베이스 타입을 넣을수 있다.
나머지 인수들은 각 속성의 설정 옵션이다. 이 또한 일반적인 데이터베이스 속성과 비슷하다.
항상 필요한 것은 아니지만 두 개의 모델은 __repr__()
메소드를 포함하는데 이 메소드는 디버깅이나 테스트용으로 사용하는 문자열 표현식을 전달한다.
관계
관계형 데이터베이스는 관계를 통해 서로 다른 테이블의 행들을 연결한다.
위 그림은 사용자(user)와 규칙(roles) 사이의 간단한 관계를 보여준다. 이것은 규칙으로부터 사용자까지의 일대다(one-to-many)
관계를 보여주는데 하나의 규칙은 많은 사용자에게, 사용자는 오직 하나의 규칙을 갖는다.
1
2
3
4
5
6
7
class Role(db.Model):
#....
users = db.relationship('User', backref='role')
class User(db.Model):
#...
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
위의 그림에서 본 것처럼, 관계는 외래키의 사용자를 통해 두 개의 행을 연결한다. User 모델에 추가된 role_id 열은 외래키로 정의되고 이것은 관계를 만든다.
rolse.id
인수는 열이 roles 테이블에있는 행에서 id값을 갖는 것으로 해석된다.
db.relationship()의 첫 번째 인수는 관계의 다른 쪽에 어떤 모델이 있는지를 나타낸다. 이 모델은 클래스가 아직 정의되지 않았다면 문자열로 제공된다.
두번째 backref 인수는 User모델에 role 속성을 추가하여 관계의 반대 방향을 정의한다. 이 속성은 Role 모델이 외래키 대신 오브젝트에 접근하도록 role_id 대신에 사용된다.
관계에는 일대다 외에 다른 타입이 있다. 일대일
관계는 userlist 옶견을 사용하여 db.relationship() 정의에서 False로 설정하면된다. 다대일
관계는 테이블이 반대라면 일대다로 표현된다. 조금 복잡한 다대다
의 경우는 관련 테이블(association table)
이라고 하는 추가 테이블이 필요하다. 다대다 관계에 대해서는 나중에 다시 알아보자.