SQLAlchemy Classical Mappings

안녕하세요. 오늘은 SQLAlchemy의 Mapping에 대해서 이야기 해볼게요. 우리가 MVC로 API를 작성할때 Database에 접근하려면 보통 Model을 사용하지요. SQLAlchemy는 Model을 정의하고 해당 모델을 Table과 Mapping할수 있는 여러가지 방법을 제공하고 있습니다. 이번 시간에는 그중 mapper()함수를 이용한 Classical Mappings에 대해서 이야기해볼게요.

일단 mapper()함수를 사용하지 않고 Model을 만들려면 아래와같이 클래스안에 Table명과 Colum들을 상단에 우선 정의한 후에 해당 Model에서 추가적으로 처리하고 싶은 로직들을 클래스안에 구현하면 됩니다.

from sqlalchemy import Column, Integer, String

class User(Base):
    __tablename__ = 'user'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    fullname = Column(String)
    password = Column(String)

    def __init__(self, name, fullname, password):
        self.name = name
        self.fullname = fullname
        self.password = password

    def __repr__(self):
        return "<User('%s', '%s', '%s')>" % (self.name, self.fullname, self.password)

물론 이렇게 해도 아무런 문제가 되지 않습니다만, Model에는 로지컬한 부분만 남기고 Database Table에 연결되는 항목들만 따로 Mapping을 시켜준다면 아무래도 코드도 간결해지고 보기에도 편해지겠죠.

그래서 제공하는것이 바로 mapper()함수를 이용하는 Classical Mappings방식입니다. 우선 가장먼저 해야할일은 Database의 Table을 코드에 기술하는 것입니다.

from sqlalchemy import Table, MetaData, Column, Integer, String, ForeignKey
metadata = MetaData()
user = Table('user', metadata,
            Column('id', Integer, primary_key=True),
            Column('name', String(50)),
            Column('fullname', String(50)),
            Column('nickname', String(12))
        )

Table을 기술하려면, sqlalchemy모듈에서 Table이라는 함수를 import하셔야합니다. 그리고 Table()함수의 가장 첫 인자로는 Database의 Table명을 적어주시고, 다음으로는 MetaData 클래스를 구현한 metadata객체를 넘겨줍니다. 그리고 그 뒤로 칼럼들을 선언하여 나열하면되는데 이때 칼럼들이 metadata객체의 일부로 저장되어 user에 들어가게 됩니다. Table의 정의가 완료되었다면 그 다음으로는 User Model을 아래와 같이 정의해주세요.

class User(object):
    def __init__(self, name, fullname, nickname):
        self.name = name
        self.fullname = fullname
        self.nickname = nickname

그리고 나서 두개를 아래와 같이 mapper()함수를 이용하여 Mapping해주면 끝입니다. 아래는 완성된 코드입니다.

from sqlalchemy import Table, MetaData, Column, Integer, String, ForeignKey
from sqlalchemy.orm import mapper

metadata = MetaData()

user = Table('user', metadata,
            Column('id', Integer, primary_key=True),
            Column('name', String(50)),
            Column('fullname', String(50)),
            Column('nickname', String(12))
        )

class User(object):
    def __init__(self, name, fullname, nickname):
        self.name = name
        self.fullname = fullname
        self.nickname = nickname

mapper(User, user)

이렇게 해주면 쿼리할때 User Model을 넘겨주면 user테이블과 mapping된 Column에 각각 값이 적용이 되게 되는것이지요. 그걸 전문용어로는 ORM이라고 합니다. 결국 mapper()를 호출하면 User Model클래스에 테이블명과 칼럼들이 자동으로 들어가는거에요. 마치 가장 처음에 mapper를 사용하지 않고 그냥 정의했을때처럼 말이죠. 그냥 mapper를 사용하지 않고 사용하는게 더 쉽고 편하다고요? ㅎㅎ 그래도 클래스하나에 다 때려넣는것보다 이렇게 나눠서 보니까 더 간결한것 같지 않나요? 조금이나마 도움이 되셨기를 바래요^^

Source: https://docs.sqlalchemy.org/en/13/orm/mapping_styles.html#classical-mapping