Manager와 QuerySet을 커스텀하여 재사용 가능한 쿼리 만들기
Django ORM의 Custom Manager와 Custom QuerySet을 활용하여 복잡하고 반복적인 쿼리를 모델 레벨에 캡슐화하고 재사용하는 방법
왜 Manager와 QuerySet을 커스텀해야 하는가?
안티 패턴
여러 View에서 동일한 필터링 로직을 반복 작성
비즈니스 로직이 View 전반에 흩어짐
조건 변경 시 모든 관련 코드를 찾아 수정해야 함
개선된 패턴
모델 레벨에서 재사용 가능한 쿼리 메서드 정의
View 로직의 간결성과 명확성 확보
코드 유지보수성과 테스트 용이성 향상
Manager와 QuerySet의 관계
구분
Manager
QuerySet
역할
모델과 데이터베이스의 주요 인터페이스
체인 가능한 연산을 통한 레코드 집합 관리
반환값
대부분 QuerySet 반환
항상 QuerySet 반환
커스텀 목적
테이블 전체 작업, 기본 QuerySet 변경
체인 가능한 필터링 메서드 추가
단계별 구현
1단계: Custom QuerySet 정의
class PostQuerySet(models.QuerySet):
def published(self):
return self.filter(
published_at__isnull=False,
published_at__lte=timezone.now(),
is_deleted=False
)
def with_details(self):
return self.select_related('author').annotate(
comment_count=Count('comments')
)2단계: Custom Manager 정의
class PostManager(models.Manager):
def get_queryset(self):
return PostQuerySet(self.model, using=self._db)
def published(self):
return self.get_queryset().published()
def with_details(self):
return self.get_queryset().with_details()3단계: 모델에 Manager 연결
class Post(models.Model):
# 필드 정의
title = models.CharField(max_length=200)
content = models.TextField()
published_at = models.DateTimeField(null=True, blank=True)
is_deleted = models.BooleanField(default=False)
# Manager 연결
objects = PostManager()실무 팁 및 주의사항
get_queryset 오버라이딩 주의점
기본 필터를 적용할 때 관리자 페이지에서 문제 발생 가능
여러 Manager 사용으로 해결
class Post(models.Model):
objects = models.Manager() # 기본 Manager
published_objects = PublishedPostManager() # 커스텀 ManagerViewSet에서의 활용
class PostViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = PostSerializer
def get_queryset(self):
return Post.objects.published().with_details()메서드 분류 기준
QuerySet 메서드: 결과물이 QuerySet인 경우, 체이닝 필요한 경우
Manager 메서드: 객체 생성/수정, 테이블 전체 작업하는 경우
주요 장점
재사용성: 공통 쿼리 로직의 중앙 집중 관리
가독성: 명확하고 직관적인 코드 작성
캡슐화: 비즈니스 규칙을 모델 계층에 캡슐화
테스트 용이성: 각 메서드의 독립적 유닛 테스트 가능
체이닝: 직관적인 메서드 체이닝 지원
Last updated
