파이썬의 객체는 _로 시작하는 속성을 가리는 은닉화의 속성을 가지고 있다. 그렇기 때문에 SQLModel에서도 _를 포함한 필드를 가져올 수 없는 이슈가 있다. 필자는 작업 중에 사용한 테이블에 _TIMESTAMP 와 같은 필드가 있어 이런 이슈를 직면하게 되었다. 이 이슈를 해결하기 위해 디렉터분께 질문을 드렸고, SQLModel은 기존의 SQLAlchemy의 컬럼을 사용할 수 있는 sa_column이란 프로퍼티를 찾아주셨다. sa_column은 SQLAlchemy Column의 줄임말이다.
아래는 일반적인 Post 모델이다.
class Post(Base, table=True):
id: int = Field(primary_key=True, index=True)
name: str = Field()
author: str = Field()
description: str = Field()
images: list[str] = Field(default=[])
updated_at: datetime | None = Field(nullable=True)
created_at: datetime = Field(default_factory=datetime.utcnow)
하지만 데이터베이스의 컬럼 이름은 다음과 같을 수 있다.
CREATE TABLE post (
id INT PRIMARY KEY,
name VARCHAR(255),
author VARCHAR(255),
_description VARCHAR(255),
_images TEXT,
updated_at TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
이런 상황에서 아래와 같이 sa_column 옵션에 SQLAlchemy의 Column 객체를 주면 SQLAlchemy에서 하던 것 처럼 데이터를 읽어올 수 있다.
class Post(Base, table=True):
id: int = Field(primary_key=True, index=True)
name: str = Field()
author: str = Field()
description: str = Field(sa_column=Column("_description", String))
images: list[str] = Field(sa_column=Column("_images", Text))
updated_at: datetime | None = Field(nullable=True)
created_at: datetime = Field(default_factory=datetime.utcnow)
특정 컬럼을 alias 해서 메모리에 불러오고 싶을 때 사용하는 방법인데 이렇게 유용하게 사용하게 될 줄 몰랐다! 그렇다면 sa_column에 대해서 조금만 더 파보자.
위 사진은 sqlmodel의 main.py 코드의 일부이다. Field는 함수인 것을 볼 수 있으며 sa_column 뿐만 아니라 args, kwargs도 지원하는 것을 볼 수 있다. 그렇다면 sa_column_args와 같은 전달 인자는 언제 사용될까? 이와 관련해서 조금 검색해보니 이런 스택 오버플로 글을 찾을 수 있었다.
질문의 주요 요지는 CheckConstraint 를 이용해서 Integer Field를 구현하고 싶은 것이고 답변에는
For age you could also just pass the CheckConstraint as a positional argument via sa_column_args instead of using sa_column. The SQL type Integer will be assigned by SQLModel by default because of the int annotation.
CheckConstraint 를 사용하기 위해선 sa_column_args 를 사용하라는 뜻이다. 예제는 아래와 같다.
from sqlmodel import SQLModel, Field, Column, String, CheckConstraint
from typing import Optional
class Hero(SQLModel, table=True):
__tablename__ = "heroes"
id: Optional[int] = Field(default=None, primary_key=True)
name: str = Field(sa_column=Column(String(32), unique=True, nullable=False))
age: int = Field(sa_column_args=(CheckConstraint("age>0"),))
SQL로 변환하면 아래와 같다.
CREATE TABLE heroes (
name VARCHAR(32) NOT NULL,
id INTEGER NOT NULL,
age INTEGER NOT NULL CHECK (age>0),
PRIMARY KEY (id),
UNIQUE (name)
)
'Backend > FastAPI' 카테고리의 다른 글
FastAPI SQLModel를 사용한 BaseModel 만들기 (0) | 2024.03.20 |
---|---|
[FastAPI] Docker Container에 Crontab 이용하기 (0) | 2023.07.18 |