Tortoise ORM: 다음 세대 Python ORM, 모두의 이야기
Ethan Miller
Product Engineer · Leapcell

Tortoise ORM: asyncio 기반의 강력한 객체 관계 매퍼
Tortoise ORM은 Django ORM에서 영감을 받아 Python용으로 제작된 사용하기 쉬운 asyncio ORM(객체 관계 매퍼)입니다. Django ORM의 디자인 개념을 차용했으며, 전통적인 테이블 데이터 처리뿐만 아니라 관계형 데이터도 효율적으로 관리할 수 있습니다. 성능 면에서도 다른 Python ORM에 뒤지지 않습니다.
지원하는 데이터베이스
Tortoise ORM은 현재 여러 주요 데이터베이스를 지원합니다.
- SQLite:
aiosqlite
에 의해 구동되며, 경량 애플리케이션 시나리오에 적합합니다. - PostgreSQL: 버전은 >= 9.4이어야 하며,
asyncpg
(비동기 모드) 또는psycopg
(동기 모드) 드라이버를 지원합니다. - MySQL/MariaDB:
asyncmy
드라이버의 도움으로 효율적인 연결을 달성합니다. - Microsoft SQL Server:
asyncodbc
드라이버를 통해 데이터 상호 작용을 완료합니다.
환경 설정 및 설치
- Tortoise ORM 설치
pip install tortoise-orm
- 해당 데이터베이스 드라이버 설치
- PostgreSQL (비동기):
pip install tortoise-orm[asyncpg]
- MySQL/MariaDB:
pip install tortoise-orm[asyncmy]
- SQLite: 기본적으로 지원되므로 별도의 드라이버 설치가 필요하지 않습니다.
데이터베이스 연결 구성
SQLite
연결 문자열 형식은 sqlite://DB_FILE
입니다. 예를 들어, 데이터베이스 파일이 /data/DB.sqlite3
인 경우, 전체 연결 문자열은 sqlite:///data/db.sqlite3
입니다 (슬래시 3개에 유의).
MySQL
연결 문자열 형식: mysql://user:password@host:3306/somedb
, 매개변수 설명:
user
: 데이터베이스 사용자 이름password
: 사용자 비밀번호host
: 데이터베이스 호스트 주소port
: 데이터베이스 포트 (기본값은 3306)database
: 연결할 데이터베이스 이름
PostgreSQL
- 비동기 모드:
asyncpg://postgres:pass@db.host:5432/somedb
- 동기 모드:
psycopg://postgres:pass@db.host:5432/somedb
Microsoft SQL Server
연결 문자열 형식: mssql://user:pass@host:1433/db?driver=theodbcdriver
, 매개변수 설명:
user
: 사용자 이름password
: 비밀번호host
: 호스트 주소port
: 포트 (기본값은 1433)database
: 데이터베이스 이름driver
: ODBC 드라이버 이름,odbcinst.ini
파일에서 구성해야 합니다.
데이터베이스 생성 및 초기화
from tortoise import Tortoise, run_async async def init(): # SQLite 데이터베이스를 사용하며, 파일 이름은 db.sqlite3입니다. # 그리고 모델을 포함하는 애플리케이션 이름을 "models"로 지정합니다. await Tortoise.init( db_url='sqlite://db.sqlite3', modules={'models': ['models']} ) # 데이터베이스 테이블 구조를 생성합니다. await Tortoise.generate_schemas() # safe 매개변수: True로 설정하면 테이블이 존재하지 않는 경우에만 생성됩니다. run_async(init()) # 컨텍스트를 자동으로 처리하고 작업이 끝나면 데이터베이스 연결을 닫습니다.
MySQL 데이터베이스를 사용하는 경우 먼저 tortoise-orm[aiomysql]
의존성을 설치해야 합니다.
모델 정의
from tortoise.models import Model from tortoise import fields from tortoise.manager import Manager class Team(Model): id = fields.IntField(pk=True) name = fields.TextField() class Meta: abstract = False # 추상 클래스 여부, True인 경우 데이터 테이블이 생성되지 않습니다. table = "team" # 테이블 이름, 설정하지 않으면 클래스 이름이 기본적으로 사용됩니다. table_description = "" # 테이블 주석 unique_together = () # 복합 고유 인덱스 indexes = () # 복합 비고유 인덱스 ordering = [] # 기본 정렬 manager = Manager # 사용자 정의 매니저
필드 유형
데이터 필드
from tortoise import fields fields.Field( source_field=None, # 사용자 정의 데이터베이스 열 이름 generated=False, # 데이터베이스에서 자동으로 생성되는지 여부 pk=False, # 기본 키 여부 null=False, # 필드가 비어있을 수 있는지 여부 default=None, # 기본값 unique=False, # 값이 고유한지 여부 index=False, # 인덱스를 생성할지 여부 description=None, # 필드 설명 validators=None # 유효성 검사기 목록 )
관계 필드
- 외래 키 필드
fields.ForeignKeyField( model_name, # 연결된 모델 이름, {app}.{models} 형식 related_name=None, # 역방향 해결 속성 이름 on_delete='CASCADE', # 삭제 전략, 선택 가능한 값: CASCADE, RESTRICT, SET_NULL, SET_DEFAULT db_constraint=True, # 데이터베이스에 외래 키 제약 조건을 생성할지 여부 )
- 일대일 필드
fields.OneToOneField( model_name, related_name=None, on_delete='CASCADE', db_constraint=True )
- 다대다 필드
fields.ManyToManyField( model_name, through=None, # 중간 테이블 forward_key=None, # 순방향 조회 키 backward_key='', # 역방향 조회 키 related_name='', on_delete='CASCADE', db_constraint=True )
쿼리 작업
모델은 여러 쿼리 메서드를 제공합니다.
filter(*args, **kwargs)
: 조건에 따라 데이터 필터링exclude(*args, **kwargs)
: 조건을 충족하는 데이터 제외all()
: 모든 데이터 가져오기first()
: 첫 번째 데이터 가져오기annotate()
: 집계 쿼리
filter
메서드에서 지원하는 쿼리 조건:
- 범위 쿼리:
in
,not_in
,gte
,gt
,lte
,lt
,range
- Null 값 쿼리:
isnull
,not_isnull
- 문자열 쿼리:
contains
,icontains
,startswith
,istartswith
,endswith
,iendswith
,iexact
- 전체 텍스트 검색:
search
다음은 몇 가지 구체적인 쿼리 예제입니다.
간단한 쿼리 예제
Team
모델이 정의되었다고 가정합니다.
from tortoise import run_async from models import Team # 모델이 models.py 파일에 정의되어 있다고 가정합니다. async def simple_query(): # 모든 Team 레코드 가져오기 all_teams = await Team.all() print("All teams:", all_teams) # 첫 번째 Team 레코드 가져오기 first_team = await Team.first() print("The first team:", first_team) # 조건에 따라 필터링하고 이름이 "Team A"인 팀 가져오기 filtered_teams = await Team.filter(name="Team A") print("Teams named Team A:", filtered_teams) run_async(simple_query())
범위 쿼리 예제
from tortoise import run_async from models import Team async def range_query(): # id가 5보다 큰 팀 쿼리 greater_than_5 = await Team.filter(id__gt=5) print("Teams with id greater than 5:", greater_than_5) # id가 2와 8 사이인 팀 쿼리 (2와 8 포함) in_range = await Team.filter(id__range=(2, 8)) print("Teams with id between 2 and 8:", in_range) # id가 [1, 3, 5]에 없는 팀 쿼리 not_in_list = await Team.filter(id__not_in=[1, 3, 5]) print("Teams whose id is not in [1, 3, 5]:", not_in_list) run_async(range_query())
문자열 쿼리 예제
from tortoise import run_async from models import Team async def string_query(): # 이름에 문자열 "team"이 포함된 팀 쿼리 (대소문자 구분 없음) contains_team = await Team.filter(name__icontains="team") print("Teams whose name contains team (case-insensitive):", contains_team) # 이름이 "A"로 시작하는 팀 쿼리 (대소문자 구분) startswith_A = await Team.filter(name__startswith="A") print("Teams whose name starts with A:", startswith_A) # 이름이 "B"로 끝나는 팀 쿼리 (대소문자 구분 없음) endswith_B = await Team.filter(name__iendswith="B") print("Teams whose name ends with B (case-insensitive):", endswith_B) run_async(string_query())
더 자세한 사용법은 Tortoise ORM 공식 문서를 참조하십시오.
Leapcell: 최고의 서버리스 웹 호스팅
마지막으로, Python 서비스 배포에 가장 적합한 플랫폼을 추천하고 싶습니다: Leapcell
🚀 좋아하는 언어로 빌드하세요
JavaScript, Python, Go 또는 Rust로 쉽게 개발하세요.
🌍 무제한 프로젝트를 무료로 배포하세요
사용한 만큼만 지불하세요. 요청이나 요금이 없습니다.
⚡ 사용량 기반 요금, 숨겨진 비용 없음
유휴 요금 없이 원활한 확장성만 제공됩니다.
🔹 Twitter에서 팔로우하세요: @LeapcellHQ