[Flask] Flask-SQLAlchemy

Alexandria·2023년 11월 10일
0

Python3 Flask

목록 보기
6/14
post-thumbnail

1. Flask-SQLAlchemy

SQLAlchemy는 SQL(Structured Query Language) 데이터베이스 액세스 툴킷 및 ORM(Object-Relational Mapping) 라이브러리입니다. 데이터베이스 테이블과 파이썬 클래스 간에 매핑을 제공합니다. 이를 통해 개발자는 SQL 쿼리 대신 파이썬 객체를 사용하여 데이터를 다룰 수 있습니다.

Flask-SQLAlchemy는 SQLAlchemy의 기능을 Flask와 통합하여 데이터베이스와의 상호작용을 간편하게 만들어줍니다.

💡 본 글은 예제 코드를 이용하여 설명합니다.

2. 설정

본 예제는 데이터베이스를 MariaDB로 사용하였습니다.

flask/source/config.py를 살펴보면 데이터베이스에 접속하기 위해 각정 정보를 조합하여 링크를 생성합니다.

SQLALCHEMY_TRACK_MODIFICATIONS는 변경을 자동으로 추적하고, 변경 사항을 데이터베이스에 반영하는 옵션으로 False를 적용하면 commit을 수동으로 호출해야 하는 단점을 가지는 반면 속도는 향상될 수 있습니다.

class Config:
	# 코드 생략
    db_pt = os.environ["MARIADB_PORT"]
    db_id = os.environ["MARIADB_USER"]
    db_pw = os.environ["MARIADB_PASSWORD"]
    db_nm = os.environ["MARIADB_DATABASE"]
    SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{db_id}:{db_pw}@db:{db_pt}/{db_nm}"
    SQLALCHEMY_TRACK_MODIFICATIONS = False

데이터베이스 정보를 통해 연결하기 위해서 flask/source/my_app/__init__.py에 코드를 작성하였습니다.

데이터베이스 객체를 생성하고 데이터베이스에 접속하여 정의된 클래스 객체들을 이용하여 테이블을 생성합니다.

db      = SQLAlchemy()
# 코드 생략

def create_app():
    app.config.from_object(obj=config["development"])

    with app.app_context():
    	# 코드 생략
        
        db.init_app(app=app)
        db.create_all()

3. 모델

flask/source/my_app/models/user.py를 살펴보면 데이터베이스의 테이블로 생성될 사용자 클래스를 정의하였습니다.

__tablename__은 데이터베이스의 테이블 이름으로 정의되며 각 클래스 변수들은 테이블의 열로 정의됩니다.

테이블의 열은 Column을 이용하여 정의할 수 있습니다.

relationship을 테이블의 열로 정의되지는 않지만, 밀접한 클래스 간 데이터를 참조하기 쉽게 하기 위하여 JOIN과 같은 역할을 합니다.

class User(db.Model, UserMixin):
    __tablename__ = "users"
    id = Column(
        INTEGER(display_width=11, unsigned=True),
        primary_key=True,
        autoincrement="auto",
        comment="사용자 식별 값"
    )
    username = Column(
        VARCHAR(length=50),
        unique=True,
        nullable=False,
        comment="사용자 아이디"
    )
    password = Column(
        VARCHAR(length=255),
        nullable=False,
        comment="사용자 비밀번호"
    )
    roles = relationship(
        argument="Role",
        secondary="rel_user_roles",
        backref=backref(name="users", lazy=True),
        uselist=True
    )
    comments = relationship(
        argument="Comment",
        secondary="rel_user_comments",
        backref=backref(name="users"),
        uselist=True
    )
    
    def __init__(self, username:str, password:str, roles:list):
        self.username = username
        self.password = generate_password_hash(password=password)
        self.roles = roles
    # 코드 생략

사용자마다 역할을 다수 가질 수 있기 때문에 uselist가 True로 설정되게 하였으며, Role이라는 역할 테이블과 rel_user_roles라는 중간 테이블을 이용하여 User 객체가 가지는 역할을 쉽게 접근할 수 있습니다.

user_roles = [role.name for role in current_user.roles]

4. 쿼리

4.1. 생성(INSERT)

flask/source/my_app/views/index.py는 사용자 객체를 생성하고 데이터베이스에 적용하는 예제입니다.

모델을 정의 시 필요한 필드들을 클래스 객체를 통해 추가합니다. id 는 autoincrement이기 때문에 사용자가 정의할 필요가 없습니다.

user = User(
	username=form.username.data,
	password=form.password.data,
	roles=[role]
)

이후, SQLAlchemy 객체를 이용하여 데이터베이스에 적용하기 위해 commit을 사용합니다.

db.session.add(instance=user)
try:
	db.session.commit()

위 코드를 통해 데이터베이스에 적용된 데이터는 아래와 같은 형식이 됩니다.

  • users 테이블
idusernamepassword
2user~~~
  • rel_user_roles 테이블
iduser_idrole_id
222

4.2. 조회(SELECT)

flask/source/my_app/views/index.py는 데이터베이스에서 사용자를 조회하는 코드입니다.

객체의 query를 이용하여 데이터베이스 질의를 하며, filter_by를 이용하여 조건을 붙입니다.

검색된 결과 중 첫번째 데이터를 뽑기 위해서는 first()를 호출하며, 모든 데이터를 뽑기 위해서는 all()을 호출합니다.

# 코드 생략
user = User.query.filter_by(username=form.username.data).first()

filter_by가 아닌 filter를 사용하여도 됩니다. 사용 방법은 아래와 같이 filter_by와는 차이가 있음을 유의합니다.

user = User.query.filter(User.username==form.username.data).first()

4.3. 수정(UPDATE)

flask/source/my_app/views/board.py는 게시글을 수정하는 함수입니다.

post라는 모델의 필드 중 title과 content라는 필드에 폼으로부터 전달된 데이터를 저장합니다.

post.title = form.title.data
post.content = form.content.data

이후, 데이터베이스에 적용하기 위해 commit을 사용합니다.

db.session.commit()

4.4. 삭제(DELETE)

flask/source/my_app/views/board.py는 게시글을 삭제하는 함수입니다.

post라는 모델을 delete 함수에 전달 후 commit하여 적용하면 데이터베이스에서 해당 데이터가 삭제됩니다.

db.session.delete(instance=post)
db.session.commit()
profile
IT 도서관

0개의 댓글