본문 바로가기
Web developer/Flask

[Flask] SQLAlchemy #1

by doongjun 2020. 10. 13.

hello.py

from flask import Flask

import os
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)

basedir = os.path.abspath(os.path.dirname(__file__)) #파일의 절대경로 저장
db_url = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SQLALCHEMY_DATABASE_URI'] = db_url
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app) #SQLAlchemy를 인스턴스화


class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    loginname = db.Column(db.String(64), unique=True, index=True)
    # relationship
    role_id = db.Column(db.Integer, db.ForeignKey("roles.id"))

    def __repr__(self):
        return "<User {}>".format(self.loginname)


class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    rolename = db.Column(db.String(64), unique=True)
    # relationship
    users = db.relationship('User', backref='role')

    def __repr__(self):
        return "<Role {}>".format(self.rolename)


@app.shell_context_processor
def make_shell_context():
    return dict(db=db, User=User, Role=Role)

파이썬 데이터베이스 프레임워크

 

파이썬은 오픈소스와 상용 데이터베이스에 대한 대부분의 엔진을 위한 패키지를 갖고 있다. flask는 어떤 데이터베이스 패키지를 사용하든 제한이 없으므로 원한다면 MySQL, Postgre, SQLite, 레디스, 몽고DB, 카우치DB를 사용할 수 있다.

 

평가 요소

-사용 편의성

-성능

-호환성

-플라스크 통합

 

Flask-SQLAlchemy를 이용한 데이터베이스 관리

 

Flask-SQLAlchemy는 플라스크 어플리케이션 안에 있는 SQLAlchemy의 사용을 간단하게 하는 플라스크 확장이다. SQLAlchemy는 여러 데이터베이스 백엔드를 지원하는 강력한 관계형 데이터베이스 프레임워크다.

Flask-SQLAlchemy는 관리자 모드에서 pip를 사용하여 설치한다.

설치 코드

pip install flask-sqlalchemy

Successfully installed flask-sqlalchemy 라는 메세지가 보인다면 성공이다.

Flask-Alchemy에서, 데이터베이스는 URL로서 지정된다.

Flask-SQLAlchemy 데이터베이스 URL

위 url에서 hostname은 데이터베이스 서비스를 제공하는 서버를 말한다.

이 글에서 SQLite 데이터베이스를 사용하려고 한다. 

SQLite는 서버를 가지고 있지 않으므로 hostname, username, password는 데이터베이스에 대한 파일이름이 된다.

 

환경설정

#1.테이블 만들기

db.create_all() 함수는 db.Model에 대응하는 모든 subclass들을 찾고 이에 대응하는 테이블들을 DB에 저장한다.

>>> from hello import db
>>> db.create_all()

위 코드를 실행한 후 디렉터리를 체크하면 data.sqlite라는 새로운 파일이 생긴 것을 확인할 수 있다.

#2.행 추가하기

>>> admin_role=Role(rolename='Admin')
>>> mod_role=Role(rolename='Modertor')
>>> user_role=Role(rolename='User')
>>> user_john=User(loginname='john', role=admin_role)
>>> user_susan=User(loginname='susan', role=user_role)
>>> user_david=User(loginname='david', role=user_role)

오브젝트는 단지 Python에만 존재하며 아직 DB에는 작성되지 않았다. id값이 설정되지 않았기 때문이다.

>>> print(admin_role.id)
None
>>> print(mod_role.id)
None
>>> print(user_role.id)
None

DB에 대한 변화는 session을 통해 관리된다. Flask-SQLAlchemy에서는 db.session으로 제공한다.

데이터베이스 작성을 위해 오브젝트를 준비하기 위해서는 오브젝트가 session에 추가되어야 한다.

DB에 오브젝트를 작성하기 위해서 commit()을 해야한다는 점 잊지말자.

>>> db.session.add(admin_role)
>>> db.session.add(mod_role)
>>> db.session.add(user_role)
>>> db.session.add(user_john)
>>> db.session.add(user_susan)
>>> db.session.add(user_david)
>>> db.session.commit()
더보기

행의 수정

admin_role.rolename = 'Administrator'
db.session.add(admin_role)
db.session.commit()

행의 삭제

db.session.delete(mod_role)
db.session.commit()

다시 id속성을 체크해보면

>>> print(admin_role.id)
1
>>> print(mod_role.id)
2
>>> print(user_role.id)
3

#3. 행의 쿼리 사용하기

Flask-SQLAlchemy는 각 Model 클래스마다 query 객체를 사용할 수 있다.

모델을 위한 가장 기본적 쿼리는 그에 대응하는 테이블의 전체 내용을 리턴하는 것이다.

filters의 사용을 통해 더 정확한 database검색을 실행할 수도 있다.

>>> Role.query.all()
[<Role Admin>, <Role Modertor>, <Role User>]
>>> User.query.all()
[<User john>, <User susan>, <User david>]
>>> User.query.filter_by(role=user_role).all()
[<User susan>, <User david>]

native SQL쿼리문을 조사할 수도 있다.

>>> str(User.query.filter_by(role=user_role))
'SELECT users.id AS users_id, users.loginname AS users_loginname, users.role_id AS users_role_id \nFROM users \nWHERE ? = users.role_id'

쉘 세션을 종료(exit()) 하면 이전 예제에서 생성된 객체들은 파이썬 객체로서 존재를 멈추고 데이터베이스 테이블에 있는 행으로 존재하게 된다. 새로운 쉘 세션을 시작한다면 데이터베이스 행에서 파이썬 객체를 재생성해야한다.

더보기

 종료 후 확인했을 때 오류가 나타나는 것을 확인할 수 있다.

>>> exit()

(flask) D:\subject\class-mobile-programming\ch06>flask shell
Python 3.7.9 (default, Aug 31 2020, 17:10:11) [MSC v.1916 64 bit (AMD64)] on win32
App: hello [production]
Instance: D:\subject\class-mobile-programming\ch06\instance
>>> print(admin_role.id)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
NameError: name 'admin_role' is not defined
>>> print(mod_role.id)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
NameError: name 'mod_role' is not defined
>>> print(user_role.id)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
NameError: name 'user_role' is not defined
>>> db
<SQLAlchemy engine=sqlite:///D:\subject\class-mobile-programming\ch06\data.sqlite>
>>> User
<class 'hello.User'>

데이터베이스 행에서 파이썬 객체를 재생성하는 방법

'User' 라는 이름의 사용자 규칙을 로드하는 쿼리를 호출한다.

>>> user_role=Role.query.filter_by(rolename='User').first()
>>> user_role
<Role User>

위의 경우 query가 all() 대신에 first() 메서드로 실행되었다.

all()은 질의 모든 결과들을 list로 리턴한다.

first()는 첫번째 결과 혹은 결과가 없으면 None을 리턴한다.

'Web developer > Flask' 카테고리의 다른 글

[Flask] Jinja2 Template #1  (0) 2020.10.30
[Flask] Bootstrap  (0) 2020.10.30
[Flask] Blueprint  (0) 2020.10.24
[Flask] 대규모 Application 구조  (0) 2020.10.24
[Flask] SQLAlchemy #2  (0) 2020.10.14

댓글