Peewee: Python 역사상 가장 우아한 ORM
Ethan Miller
Product Engineer · Leapcell

Peewee 쿼리 튜토리얼: 가벼운 ORM으로 효율적인 데이터 조작
Python 데이터베이스 개발에서 객체 관계 매핑(ORM) 라이브러리는 개발자에게 필수적인 도구입니다. 경량 ORM인 Peewee는 단순성과 사용 용이성으로 두각을 나타냅니다. 이 튜토리얼에서는 Peewee의 쿼리 기능을 자세히 살펴보고, Leapcell과 유사한 플랫폼에 배포된 사용자 서비스의 컨텍스트에서 예제를 제공하고, SQLAlchemy와 비교하고, Peewee의 장점을 분석합니다.
I. Peewee의 기본 쿼리 작업
(1) 레코드 생성
Leapcell 클라우드 플랫폼과 유사한 사용자 서비스에서 username
, email
및 plan_type
(구독 플랜)을 포함한 사용자 정보를 저장하는 User
모델이 있다고 가정합니다. Peewee를 사용하여 새 사용자 레코드를 만드는 것은 간단합니다.
from peewee import * # 데모를 위해 SQLite 사용; Leapcell 배포에서 실제 데이터베이스로 교체 db = SqliteDatabase('leapcell_users.db') class User(Model): username = CharField() email = CharField(unique=True) plan_type = CharField() class Meta: database = db db.connect() db.create_tables([User]) # Model.create()를 사용하여 새 사용자 생성 new_user = User.create(username='test_user', email='test@example.com', plan_type='basic')
User.create()
메서드는 모델의 필드와 일치하는 키워드 인수를 사용하고, 새 레코드를 삽입하고, 생성된 모델 인스턴스를 반환합니다.
(2) 일괄 삽입
Leapcell로 사용자를 마이그레이션하는 등 대량 데이터 삽입의 경우:
user_data = [ {'username': 'user1', 'email': 'user1@example.com', 'plan_type': 'pro'}, {'username': 'user2', 'email': 'user2@example.com', 'plan_type': 'basic'}, {'username': 'user3', 'email': 'user3@example.com', 'plan_type': 'enterprise'} ] # insert_many()를 사용하여 일괄 삽입 with db.atomic(): User.insert_many(user_data).execute()
insert_many()
는 사전 목록을 받아 단일 데이터베이스 작업으로 여러 레코드를 삽입합니다. 이는 create()
를 반복하는 것보다 훨씬 효율적입니다.
(3) 레코드 업데이트
Leapcell에서 사용자 구독 요금제를 업데이트하려면:
# 단일 사용자 업데이트 user_to_update = User.get(User.username == 'test_user') user_to_update.plan_type = 'pro' user_to_update.save() # 일괄 업데이트: 모든 basic 사용자를 pro로 업그레이드 query = User.update(plan_type='pro').where(User.plan_type == 'basic') query.execute()
단일 인스턴스 업데이트에는 save()
를 사용하고, 대량 작업에는 Model.update().where()
를 사용합니다.
(4) 레코드 삭제
플랫폼에서 사용자를 제거하려면:
# 단일 사용자 삭제 user_to_delete = User.get(User.username == 'user1') user_to_delete.delete_instance() # 여러 사용자 삭제 (예: 비활성 계정) query = User.delete().where(User.is_deleted == True) query.execute()
개별 레코드에는 delete_instance()
를 사용하고, 조건부 삭제에는 Model.delete().where()
를 사용합니다.
(5) 레코드 쿼리
- 단일 레코드 쿼리:
get()
또는get_by_id()
로 특정 사용자 검색:
# 기본 키로 쿼리 user = User.get_by_id(1) print(user.username, user.email, user.plan_type) # 다른 필드로 쿼리 user = User.get(User.email == 'test@example.com')
이러한 메서드는 기준과 일치하는 레코드가 없으면 DoesNotExist
를 발생시킵니다.
- 여러 레코드 쿼리:
select()
를 사용하여 레코드를 검색하고 반복합니다.
# 모든 사용자 반복 for user in User.select(): print(user.username, user.email) # 슬라이싱 및 인덱싱 users_subset = User.select()[:5] for user in users_subset: print(user.username)
Peewee는 기본적으로 쿼리 결과를 캐시합니다. 대용량 데이터 세트의 메모리 효율적인 처리를 위해 Select.iterator()
를 사용합니다.
- 레코드 필터링: Peewee는 다양한 필터링 방법을 지원합니다.
# 단순 필터 pro_users = User.select().where(User.plan_type == 'pro') # 비트 연산자를 사용한 복잡한 조건 active_pro_users = User.select().where((User.plan_type == 'pro') & (User.is_active == True)) # IN 쿼리 specific_emails = ['user1@example.com', 'user2@example.com'] matching_users = User.select().where(User.email.in_(specific_emails))
- 레코드 정렬:
order_by()
를 사용하여 결과 정렬:
# 사용자 이름으로 오름차순 정렬 sorted_users = User.select().order_by(User.username) # 등록 시간별 내림차순 정렬 (registered_at 필드 가정) recent_users = User.select().order_by(-User.registered_at) # 다중 필드 정렬 multi_sorted_users = User.select().order_by(User.plan_type, User.username)
- 페이지 매김 및 계산: 대용량 데이터 세트 처리에 필수적입니다.
# 결과 페이지 매김 (페이지 2, 페이지당 10개 레코드) paged_users = User.select().order_by(User.id).paginate(2, 10) for user in paged_users: print(user.username) # 총 사용자 수 계산 user_count = User.select().count() print(f"Total users: {user_count}") # 요금제 유형별 사용자 수 계산 pro_user_count = User.select().where(User.plan_type == 'pro').count()
- 집계 및 스칼라 쿼리: 집계 함수로 데이터 분석:
from peewee import fn # 요금제 유형별 사용자 수 계산 query = (User .select(User.plan_type, fn.Count(User.id).alias('count')) .group_by(User.plan_type)) for result in query: print(result.plan_type, result.count) # 스칼라 값 검색 (예: 최대 사용자 ID) max_id = User.select(fn.Max(User.id)).scalar()
- 윈도우 함수: 결과 집합에서 계산 수행:
from peewee import Window, fn # 각 요금제 유형 내에서 등록 순위 계산 query = User.select( User.username, User.plan_type, fn.RANK().over( order_by=[User.registered_at], partition_by=[User.plan_type] ).alias('registration_rank') ) for user in query: print(user.username, user.plan_type, user.registration_rank)
- 윈도우 정의 재사용: 윈도우 객체로 복잡한 쿼리 간소화:
# 재사용 가능한 윈도우 정의 win = Window(order_by=[User.registered_at], partition_by=[User.plan_type]) query = User.select( User.username, User.plan_type, fn.RANK().over(win).alias('rank1'), fn.DENSE_RANK().over(win).alias('rank2') ).window(win) # 다중 윈도우 정의 win1 = Window(order_by=[User.registered_at]).alias('win1') win2 = Window(partition_by=[User.plan_type]).alias('win2') query = User.select( User.username, User.plan_type, fn.SUM(User.login_count).over(win1).alias('total_logins'), fn.AVG(User.login_count).over(win2).alias('avg_logins') ).window(win1, win2)
- 프레임 유형: RANGE vs ROWS vs GROUPS: 윈도우 함수 계산 제어:
# ROWS 프레임 유형의 예 class Sample(Model): counter = IntegerField() value = FloatField() class Meta: database = db db.create_tables([Sample]) # 테스트 데이터 삽입 data = [(1, 10), (1, 20), (2, 1), (2, 3), (3, 100)] Sample.insert_many(data, fields=[Sample.counter, Sample.value]).execute() # ROWS 프레임으로 누적 합계 계산 query = Sample.select( Sample.counter, Sample.value, fn.SUM(Sample.value).over( order_by=[Sample.id], frame_type=Window.ROWS ).alias('rsum') ) for sample in query: print(sample.counter, sample.value, sample.rsum)
- 데이터를 튜플 또는 사전으로 검색: 효율성을 위해 모델 인스턴스화를 건너뜁니다.
# 결과를 사전으로 반환 query = User.select(User.username, User.plan_type).dicts() for user_dict in query: print(user_dict['username'], user_dict['plan_type']) # 결과를 튜플로 반환 query = User.select(User.username, User.plan_type).tuples() for user_tuple in query: print(user_tuple[0], user_tuple[1])
- RETURNING 절: 수정된 데이터 검색 (PostgreSQL):
from peewee import PostgresqlDatabase # PostgreSQL 연결 db = PostgresqlDatabase('leapcell_db', user='user', password='password', host='localhost', port=5432) class User(Model): username = CharField() email = CharField(unique=True) plan_type = CharField() class Meta: database = db # RETURNING으로 업데이트 query = (User .update(plan_type='enterprise') .where(User.username == 'test_user') .returning(User)) for updated_user in query.execute(): print(updated_user.username, updated_user.plan_type)
- 공통 테이블 표현식(CTE): complex 쿼리 단순화:
from peewee import CTE class UserActivity(Model): user = ForeignKeyField(User) action_time = DateTimeField() class Meta: database = db db.create_tables([UserActivity]) # 평균 활동 간격을 계산하는 CTE cte = (UserActivity .select(UserActivity.user, fn.AVG(fn.JULIANDAY(UserActivity.action_time) - fn.JULIANDAY(fn.LAG(UserActivity.action_time).over(order_by=[UserActivity.user, UserActivity.action_time]))).alias('avg_interval')) .group_by(UserActivity.user) .cte('user_activity_intervals')) # 평균 간격 < 1일인 사용자 쿼리 query = (User .select(User.username) .join(cte, on=(User.id == cte.c.user)) .where(cte.c.avg_interval < 1) .with_cte(cte)) for user in query: print(user.username)
II. Peewee vs SQLAlchemy
(1) 학습 곡선
Peewee의 API는 직관적이고 초보자에게 친숙하며 쿼리 구문은 자연어와 유사합니다. SQLAlchemy는 기능이 풍부하지만 특히 고급 매핑 및 트랜잭션 관리에서 복잡성으로 인해 학습 곡선이 더 가파릅니다.
(2) 성능
단순 쿼리에서는 두 ORM 모두 유사한 성능을 보입니다. 그러나 Peewee의 경량 설계와 간결한 SQL 생성은 대규모 데이터 세트가 있는 복잡한 작업에서 우위를 점합니다. 광범위한 기능 집합으로 인한 SQLAlchemy의 오버헤드는 특정 시나리오에서 성능에 영향을 미칠 수 있습니다.
(3) 사용 사례
Peewee는 단순성과 속도가 우선시되는 빠른 프로토타입 제작 및 경량 애플리케이션에 적합합니다. Leapcell과 같은 플랫폼의 모듈에 이상적입니다. SQLAlchemy는 복잡한 관계 및 고급 트랜잭션 요구 사항이 있는 대규모 엔터프라이즈 애플리케이션에 더 적합합니다.
III. 결론
Peewee는 데이터베이스 작업에 대한 간소화된 접근 방식을 제공하므로 효율성과 사용 편의성을 우선시하는 개발자에게 최고의 선택입니다. Leapcell의 사용자 서비스 에코 시스템에서 영감을 얻은 예제를 통해 이 튜토리얼에서는 CRUD 작업, 집계 및 고급 쿼리에서 Peewee의 기능을 보여줍니다. SQLAlchemy와 비교할 때 Peewee는 더 낮은 학습 곡선, 성능상의 이점 및 빠른 개발에 대한 적합성으로 두각을 나타냅니다. 민첩성과 경량 설계가 중요한 프로젝트에는 Peewee를 선택하십시오. # Peewee 쿼리 튜토리얼: 효율적인 Python ORM
소개
Python 데이터베이스 개발에서 객체 관계 매핑 (ORM) 도구는 데이터베이스와의 상호 작용을 단순화합니다. 가볍지 만 강력한 ORM 인 Peewee는 개발자에게 데이터베이스를 쿼리하는 세련되고 효율적인 방법을 제공합니다. 로컬 또는 Leapcell과 같은 클라우드 플랫폼에 배포하든 Peewee는 뛰어난 성능을 제공합니다. 이 기사에서는 Peewee의 쿼리 기능을 살펴보고 SQLAlchemy와 대조하며 Leapcell의 에코 시스템의 실제 사례를 통해 장점을 설명합니다.
Peewee 기본 쿼리 작업
레코드 생성
Leapcell 플랫폼에서 사용자 데이터를 관리하려면 모델을 정의해야합니다.
from peewee import * # 데이터베이스에 연결 (Leapcell에서 자동 감지 가능한 구성) db = SqliteDatabase('leapcell_users.db') class BaseModel(Model): class Meta: database = db class User(BaseModel): username = CharField(unique=True) email = CharField() created_at = DateTimeField(default=datetime.datetime.now) is_active = BooleanField(default=True) class Service(BaseModel): name = CharField() user = ForeignKeyField(User, backref='services') status = CharField(default='pending') deployed_at = DateTimeField(null=True)
Leapcell에서 새 사용자를 만들려면:
# Leapcell에서 사용자 만들기 try: user = User.create(username='alice', email='alice@example.com') print(f"User {user.username} created successfully") except IntegrityError: print("Username already exists")
일괄 삽입
여러 사용자를 Leapcell로 가져 오는 중:
# Leapcell API에서 대량 사용자 데이터 시뮬레이션 users_data = [ {'username': 'bob', 'email': 'bob@example.com'}, {'username': 'charlie', 'email': 'charlie@example.com'}, {'username': 'david', 'email': 'david@example.com'} ] # Leapcell의 데이터베이스에 일괄 삽입 with db.atomic(): User.insert_many(users_data).execute()
레코드 업데이트
Leapcell에서 서비스 상태 업데이트:
# Leapcell에서 서비스 상태 업데이트 service = Service.get(Service.name == 'web-app' and Service.user == user) service.status = 'running' service.deployed_at = datetime.datetime.now() service.save()
레코드 삭제
Leapcell에서 서비스 제거:
# Leapcell에서 서비스 삭제 service = Service.get(Service.name == 'old-service' and Service.user == user) service.delete_instance()
레코드 쿼리
Leapcell에서 사용자와 해당 서비스 검색:
# Leapcell에서 활성 사용자와 실행중인 서비스 쿼리 query = (User .select(User, Service) .join(Service, JOIN.LEFT_OUTER) .where(User.is_active == True) .order_by(User.username)) for user in query: print(f"User: {user.username}") if user.services: for service in user.services: print(f" Service: {service.name} ({service.status})") else: print(" No services")
Peewee 고급 쿼리 기술
집계 쿼리
Leapcell에서 사용자별 서비스 수 계산:
# Leapcell에서 사용자별 서비스 수 계산 query = (User .select(User, fn.Count(Service.id).alias('service_count')) .join(Service, JOIN.LEFT_OUTER) .group_by(User) .order_by(SQL('service_count').desc())) for user in query: print(f"User: {user.username}, Services: {user.service_count}")
윈도우 함수
Leapcell에서 배포 순서 분석:
# 윈도우 함수로 배포 순서 분석 query = (Service .select( Service.name, Service.deployed_at, fn.RANK().over(order_by=[Service.deployed_at.desc()]).alias('deploy_rank') ) .where(Service.deployed_at.is_null(False))) for service in query: print(f"Service: {service.name}, Deployment Rank: {service.deploy_rank}")
공통 테이블 표현식
Leapcell에서 CTE를 사용하는 복잡한 쿼리:
# 지난 30 일 동안 활성 사용자와 해당 서비스 쿼리 active_users_cte = (User .select(User.id) .where(User.last_login > datetime.datetime.now() - datetime.timedelta(days=30)) .cte('active_users')) query = (Service .select(Service, User.username) .join(User) .with_cte(active_users_cte) .where(User.id == active_users_cte.c.id)) for service in query: print(f"Active User {service.user.username}'s Service: {service.name}")
ORM으로서 Peewee가 빛나는 이유
경량 설계
Peewee의 최소한의 아키텍처는 오버 헤드를 줄이므로 Leapcell과 같은 클라우드 플랫폼에 이상적입니다. 단순성 덕분에 SQLAlchemy와 같은 더 무거운 ORM에 비해 개발 및 배포 속도가 빨라집니다.
성능 우위
Peewee는 효율적인 SQL을 생성하여 대량 작업에 탁월합니다. 예를 들어, 일괄 삽입은 Leapcell에서 응용 프로그램 확장에 중요한 SQLAlchemy의 기본 방식보다 성능이 뛰어납니다.
유연한 데이터베이스 지원
Peewee는 SQLite, PostgreSQL, MySQL 등을 완벽하게 지원합니다. 이러한 유연성 덕분에 일관된 API를 유지하면서 Leapcell의 다양한 데이터베이스 제품과의 호환성이 보장됩니다.
직관적 인 API
Peewee의 Pythonic 구문은 개발자 기대치와 일치하여 상용구 코드를 줄입니다. 이 단순성 덕분에 Leapcell의 개발 주기가 가속화되어 팀이 ORM 복잡성보다는 기능에 집중할 수 있습니다.
결론
Peewee는 단순성, 성능 및 유연성을 결합한 다재다능한 ORM으로, Leapcell과 같은 클라우드 기반 서비스에 필수적인 품질입니다. 이 튜토리얼에서는 실제 사례를 통해 기본 및 고급 시나리오에서 Peewee의 기능을 보여주었습니다. SQLAlchemy와 비교했을 때 Peewee는 속도, 확장 성 및 개발자 생산성을 우선시하는 프로젝트에 선호되는 선택으로 부상했습니다.
Leapcell : 최고의 서버리스 웹 호스팅
마지막으로 Python 서비스를 배포하기에 완벽한 플랫폼을 추천합니다. Leapcell
🚀 좋아하는 언어로 빌드
JavaScript, Python, Go 또는 Rust로 쉽게 개발하십시오.
🌍 무료로 무제한 프로젝트 배포
사용한만큼만 지불하십시오 – 요청 없음, 요금 없음.
⚡ 종량제, 숨겨진 비용 없음
유휴 수수료가 없으며 원활한 확장 성만 제공됩니다.
🔹 Twitter에서 팔로우하세요 : @LeapcellHQ