이전글과 이어지는 내용이다. SQLAlchemy과 SQLModel에 대하여 알아보자.
SQLAlchemy란?
Python에서 가장 널리 사용되는 데이터베이스 ORM(Object Relational Mapper) 및 SQL 툴킷이다. SQLAlchemy는 Python 코드와 데이터베이스 간의 상호작용을 단순화하고, SQLAlchemy Core와 ORM(Object Relational Mapping)이라는 두 가지 주요 컴포넌트를 제공한다.
ORM이란?
객체 지향 프로그래밍 언어의 객체를 데이터베이스의 테이블과 매핑하여, SQL을 직접 작성하지 않고도 데이터베이스를 조작할 수 있게 해주는 도구나 기술이다.
1. SQLAlchemy의 주요 컴포넌트
- SQLAlchemy Core:
- SQLAlchemy Core는 SQL 표현 언어로, SQL 쿼리를 Python 코드로 작성하고 실행할 수 있도록 도와준다.
- SQLAlchemy Core는 SQLAlchemy ORM 없이도 독립적으로 사용할 수 있다.
- SQLAlchemy ORM:
- SQLAlchemy ORM은 Python 클래스와 데이터베이스 테이블을 매핑하여 객체 지향 방식으로 데이터를 관리한다.
- ORM을 사용하면 SQL을 직접 작성하지 않고도 데이터를 처리할 수 있다.
2. SQLAlchemy의 장점
- 강력한 데이터베이스 지원:
- MySQL, PostgreSQL, SQLite, Oracle, Microsoft SQL Server 등 다양한 데이터베이스와 호환된다.
- 고성능 쿼리 지원:
- 저수준 SQL 작업(Core)과 고수준 ORM 작업을 동시에 지원하여 다양한 요구를 충족한다.
- 관계 설정:
- 테이블 간의 관계(1:1, 1:N, N:M 등)를 손쉽게 설정할 수 있다.
- 트랜잭션 관리:
- 데이터 작업의 무결성을 유지할 수 있도록 트랜잭션 관리를 제공한다.
- 커스터마이징:
- 사용자가 SQLAlchemy의 동작을 세밀하게 제어할 수 있다.
3. SQLAlchemy가 사용되는 경우
- 대규모 프로젝트에서 복잡한 데이터베이스 작업이 필요한 경우
- SQL 작성 및 실행이 중요한 애플리케이션
- 성능과 유연성이 중요한 데이터베이스 중심 애플리케이션
4. SQLAlchemy의 예제 코드
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.orm import declarative_base, sessionmaker
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
email = Column(String)
# 데이터베이스 연결
engine = create_engine('sqlite:///example.db')
Base.metadata.create_all(engine)
# 세션 생성
Session = sessionmaker(bind=engine)
session = Session()
# 데이터 삽입
new_user = User(name="YooJaeseok", email="YooJaeseok@naver.com")
session.add(new_user)
session.commit()
SQLModel이란?
SQLAlchemy와 Pydantic의 기능을 결합하여 더 간결하고 Pythonic한 방식으로 데이터베이스 작업을 처리할 수 있는 ORM 라이브러리이다. SQLAlchemy의 강력한 기능을 그대로 활용하면서, Pydantic의 데이터 검증 및 JSON 직렬화 기능을 추가로 제공한다.
1. SQLModel의 주요 특징
- SQLAlchemy 기반:
- SQLAlchemy ORM과 Core의 모든 기능을 그대로 지원한다.
- Pydantic 통합:
- Python 타입 힌팅과 데이터 검증을 결합하여 안전하고 직관적인 데이터 처리를 제공한다.
- JSON 직렬화/역직렬화 기능이 기본 제공된다.
- 간결한 문법:
- SQLAlchemy보다 간단한 문법으로 테이블 정의와 데이터 작업을 처리할 수 있다.
- 자동 검증:
- 모델 정의 시 타입 힌트를 기반으로 입력값을 자동으로 검증한다.
2. SQLModel의 장점
- 간결성과 가독성:
- Pythonic한 문법 덕분에 코드가 간단하고 읽기 쉬워진다.
- 타입 힌팅 기반 모델:
- Python의 타입 힌팅을 완벽히 지원하여, IDE의 자동 완성과 정적 분석 도구와 잘 통합된다.
- 데이터 검증:
- Pydantic의 데이터 유효성 검사 기능이 내장되어, 잘못된 데이터 입력을 방지한다.
- SQLAlchemy 호환성:
- SQLAlchemy의 모든 기능(Core, ORM)을 그대로 사용할 수 있다.
3. SQLModel이 사용되는 경우
- 데이터 검증과 JSON 직렬화가 중요한 경우
- 타입 힌팅을 활용해 안전한 데이터 모델을 정의하고 싶은 경우
- 더 간단한 문법으로 SQLAlchemy의 기능을 사용하고 싶은 경우
4. SQLModel의 예제 코드
from sqlmodel import SQLModel, Field, create_engine, Session
class User(SQLModel, table=True):
id: int = Field(default=None, primary_key=True)
name: str
email: str
# 데이터베이스 연결
engine = create_engine('sqlite:///example.db')
SQLModel.metadata.create_all(engine)
# 세션 생성
with Session(engine) as session:
# 데이터 삽입
new_user = User(name="YooJaeseok", email="YooJaeseok@naver.com")
session.add(new_user)
session.commit()
표로 정리하자면 다음과 같다.
항목 | SQLAlchemy | SQLModel |
기능 | SQLAlchemy Core(SQL 표현 언어)와 ORM 제공 | SQLAlchemy ORM에 Pydantic 기능(검증, 직렬화)을 통합 |
사용성 | SQL 쿼리 작성 및 ORM 사용 모두 가능하지만 설정이 더 복잡 | 더 간결하고 직관적인 문법 제공 |
타입 힌팅 지원 | Python 타입 힌팅을 지원하지 않음 (추가적인 라이브러리로 지원 가능) | 타입 힌팅을 완벽히 지원 (Pydantic 기반) |
데이터 검증 | 데이터 검증 기능이 기본적으로 제공되지 않음 | Pydantic의 데이터 검증 기능을 통해 모델에서 자동 검증 가능 |
직렬화/JSON 지원 | ORM 객체를 JSON으로 직렬화하려면 별도의 코딩 필요 | Pydantic의 JSON 직렬화 기능이 기본 제공 |
주요 사용 사례 | 고성능이 필요한 프로젝트, SQL 작성이 중요한 경우 | 타입 안전성과 데이터 검증이 중요한 프로젝트, 더 간결한 코드 작성이 필요한 경우 |
코드 복잡도 | SQLModel보다 복잡 (컬럼 정의, 관계 설정 등에서 더 많은 설정 필요) | SQLAlchemy의 기능을 확장하여 더 간단한 문법으로 동일한 작업을 수행 가능 |
SQLModel은 SQLAlchemy를 기반으로 Pydantic의 데이터 검증과 직렬화 기능을 결합하여 확장된 라이브러리다. 즉, SQLModel 안에 SQLAlchemy가 포함되어 있으며, SQLAlchemy의 모든 기능을 활용하면서도 더 간단하고 Pythonic한 사용성을 제공한다.
더 이해하기 쉽게 비유하자면, SQLAlchemy는 데이터베이스와 직접 소통하는 강력한 "엔진"이고, SQLModel은 이 엔진을 기반으로 누구나 쉽게 운전할 수 있는 "자동차"와 같다. SQLAlchemy 없이는 SQLModel이 동작할 수 없지만, SQLModel을 사용하면 SQLAlchemy의 복잡성을 숨기고 더 편리하게 데이터 작업을 처리할 수 있다.
내가 사용하고 있는 data_model.py에서 사용된 SQLAlchmey와 SQLModel은 이렇다.
from datetime import datetime, time
from typing import List, Optional
import phonenumbers
from pydantic import field_validator
from sqlmodel import Field, Relationship, SQLModel
from sqlalchemy import text
from pydantic import validator
class AdministrativeDivision(SQLModel, table=True):
__tablename__ = "administrative_division"
id: int | None = Field(default=None, primary_key=True)
city_province: str = Field(max_length=50)
city_county: str = Field(max_length=50)
class Member(SQLModel, table=True):
__tablename__ = "member"
id: Optional[int] = Field(default=None, primary_key=True)
name: str = Field(..., max_length=50, nullable=False) # VARCHAR(50)
email: str = Field(..., max_length=255) # VARCHAR(255)
access_token: str = Field(max_length=2083)
refresh_token: str = Field(max_length=2083)
oauth: str = Field(max_length=50)
nickname: Optional[str] = Field(default=None, max_length=50)
sex: Optional[str] = Field(default=None, max_length=10)
picture_url: Optional[str] = Field(default=None, max_length=2083)
birth: Optional[datetime] = None
address: Optional[str] = Field(default=None, max_length=255)
zip: Optional[str] = Field(default=None, max_length=10)
phone_number: Optional[str] = Field(default=None, max_length=20)
voice: Optional[str] = Field(default=None, max_length=255)
role: Optional[str] = Field(default=None, max_length=10)
created_at: datetime = Field(
sa_column_kwargs={"server_default": text("CURRENT_TIMESTAMP"), "nullable": False}
)
updated_at: datetime = Field(
sa_column_kwargs={"server_default": text("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"), "nullable": False}
)
plans: List["Plan"] = Relationship(back_populates="member")
# 전화번호 유효성 검사
@field_validator("phone_number")
def check_phone_number(cls, values):
phone_number = values.get('phone_number')
try:
parsed_number = phonenumbers.is_valid_number(phone_number)
if not parsed_number:
raise ValueError(f"Invalid phone number: {phone_number}")
except phonenumbers.phonenumberutil.NumberParseException as e:
raise ValueError(f"Invalid phone number: {phone_number}") from e
return values
1. 클래스 상속 및 테이블 정의
- SQLModel을 상속받은 클래스는 데이터베이스 테이블로 매핑된다.
- table=True를 통해 클래스가 데이터베이스 테이블로 사용된다는 것을 명시한다.
class Member(SQLModel, table=True):
2. 필드 정의
- Field는 SQLAlchemy의 Column과 동일한 역할을 한다.
- 데이터 타입과 제약 조건(예: primary_key, nullable, max_length)을 설정한다.
id: int | None = Field(default=None, primary_key=True)
name: str = Field(..., max_length=50, nullable=False)
3. 관계 설정
- Relationship은 SQLAlchemy의 relationship 기능을 사용하여 테이블 간 관계를 정의한다.
- Member 테이블과 Plan 테이블 간에 일대다 관계를 설정
plans: List["Plan"] = Relationship(back_populates="member")
4. SQLAlchemy Core의 text 사용
- SQLAlchemy Core에서 제공하는 text()를 사용하여 SQL 문법을 명시적으로 정의
- 예: CURRENT_TIMESTAMP를 기본값으로 설정
from sqlalchemy import text
created_at: datetime = Field(
sa_column_kwargs={"server_default": text("CURRENT_TIMESTAMP"), "nullable": False}
)
5. 데이터 타입 관리
- SQLAlchemy는 Field 정의 시 데이터 타입을 SQL 타입으로 매핑한다.
- 예: str → VARCHAR, datetime → DATETIME.
'Python' 카테고리의 다른 글
[Python] FastAPI와 React 연동 및 데이터 흐름과 처리 과정 (0) | 2025.01.31 |
---|---|
[Python] Google Maps & SerpAPI를 활용한 맛집 추천 개발기 (0) | 2025.01.30 |
[Python] Pydantic으로 안전하고 효율적인 데이터 검증하기 (0) | 2025.01.25 |
[Python] async/await로 배우는 비동기 프로그래밍 (0) | 2025.01.11 |
[Python] 크롤링(crawling) 사용해보기: Velog 크롤링 (0) | 2025.01.10 |