Django 내부 분석: 'Manager'는 무엇일까?

July 03, 2023

필자는 한 회사의 Django BackEnd 인턴 과정 중, 인증/인가 기능 구현 Task를 진행하였다. 이를 위해 첫 번째로 Custom UserModel을 만드는 과정에서 시작된, Django의 Manager에 대해 자세히 알아본 바를 공유하려 한다. 처음에는 단순히 Custom UserModel을 구현하는 것이 목적이었지만, 이 과정을 통해 필자는 Django의 핵심 구성 요소 중 하나인 Manager에 대한 이해를 조금 더 넓힐 수 있었다고 생각한다.

Manager?

# AbstractBaseUser도 models.Model을 상속받는다.
class MyUser(AbstractBaseUser):
    email = models.EmailField(
        verbose_name="email address",
        max_length=255,
        unique=True,
    )
    date_of_birth = models.DateField()
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    objects = MyUserManager()

만약 UserModel의 자유도를 높이기 위해 AbstractBaseUser를 상속받게 된다면, 위처럼 BaseUserManager를 상속받는 Custom UserManager를 objects로서 명시해주어야 한다. 예시에서는 MyUserManager가 그 역할을 하였다. 이 구문의 필요성에 대해 처음부터 궁금증이 생겼다. 평소에 Model.objects라는 구문을 많이 사용하긴 했지만, ORM을 사용하기 위해 존재하는 정도로만 알았고, 이것이 어떻게 Model 클래스에 부여되고 동작하는지 알지 못했기 때문이다. 애초에 Manager의 존재를 알지 못했다.

공식 문서에서의 설명

A Manager is the interface through which database query operations are provided to Django models. At least one Manager exists for every model in a Django application.

The way Manager classes work is documented in Making queries; this document specifically touches on model options that customize Manager behavior.

--Django Documentation

위 인용문과 같이 Manager는 데이터베이스와 상호작용하여 쿼리 동작을 수행할 수 있게 해주는 인터페이스임을 알 수 있다. 즉, Django ORM 시스템의 구성요소라고 볼 수 있다. 그리고 Model 클래스는(django.db.models.Model) 기본적으로 Manager를 가지고 있는 것 또한 알 수 있다. 따라서 Model 서브클래스 또한 Manager를 가지고 있다.

더 나아가 Making queries 링크 내용을 요약하면, ManagerModel 객체를 데이터베이스에서 CRUD 할 수 있도록 해주고 여러가지 상황에 대한 쿼리셋을 만들어주는 기능을 지원함을 알 수 있다.

Manager가 Model 클래스에 부여되는 방식

Django에서 Manager가 어떻게 Model 클래스에 부여되는지 이해하기 위해서는 Django의 Model 상속 체계와 메타클래스 구조를 살펴볼 필요가 있다. 우리가 Model을 사용하기 위해 상속받는 models.Model 클래스는 models.ModelBase라는 메타클래스를 사용한다. ModelBaseModel 클래스가 정의될 때 각종 설정을 처리하고, Model 클래스를 최종적으로 생성하는 역할을 수행한다.

실제로 ModelBase 내부의 _prepare 메서드에서 Model 클래스에 Manager가 부여되는 것을 확인할 수 있다. 만약 개발자가 Model 서브클래스에 명시적으로 Manager를 지정하지 않은 경우, ModelBase는 기본 Manager 객체를 생성하여 objects라는 이름으로 Model 클래스에 추가하는 것이다 (더 내부적으로는 setattr을 사용한다). 이 과정을 통해 Model 클래스는 별다른 개발자의 개입 없이도 데이터베이스 쿼리를 수행할 수 있는 기본 인터페이스를 갖추게 된다. 즉, Model.objects.all() 등을 사용할 수 있게 된다, 이는 데이터베이스에서 모든 레코드를 조회하는 기본적인 방법이다.

# models/base.py
class Model(AltersData, metaclass=ModelBase):
    ...

class ModelBase(type):
    ...
    if not opts.managers:
        if any(f.name == "objects" for f in opts.fields):
            raise ValueError(
                "Model %s must specify a custom Manager, because it has a "
                "field named 'objects'." % cls.__name__
            )
        manager = Manager()
        manager.auto_created = True
        cls.add_to_class("objects", manager)
    ...

Custom Manager

개발자가 Model 서브클래스에 명시적으로 Manager를 지정하지 않은 경우, ...

바로 윗 문단에서 위와 같은 문장이 있었다. 더불어 두 번째 문단에서 AbstractBaseUser를 상속받은 Custom UserModel에서는 BaseUserManager를 상속받는 Custom UserManager가 필요하다고 하였다.

위로 유추해볼 수 있는 것은, Manager를 우리가 직접 만들 수 있다는 것이다.

예를 들어, 다음과 같은 Model이 있다고 하자.

class ColorManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(is_available=True)

    def by_color(self, color):
        return self.get_queryset().filter(color=color)

class Pencil(models.Model):
    color = models.CharField(max_length=20)
    is_available = models.BooleanField(default=True)
    objects = ColorManager()

class Pen(models.Model):
    color = models.CharField(max_length=20)
    is_available = models.BooleanField(default=True)
    objects = ColorManager()

필드의 이름이 같은 PencilPen 모델을 준비하였다. 이들은 ColorManager라는 models.Manager의 서브클래스를 objects로 사용한다. ColorManagerget_queryset 메서드를 통해 기본적으로 모든 쿼리에 대해 is_availableTrue인 레코드를 필터링하며, 추가적으로 by_color 메서드를 통해 특정 색상의 연필이나 펜을 조회할 수 있는 기능을 제공한다. 예를 들어, Pencil.objects.by_color("red")를 실행하면 빨간색이면서 사용 가능한 연필만을 조회할 수 있다.

물론, color_objects = ColorManager()와 같이 작성하여 기본 Manager와 Custom Manager를 함께 사용할 수도 있다.

이처럼 Custom Manager를 사용함으로써, 특정 쿼리 로직을 커스터마이징 할 수 있다. 이를 통해 높은 재사용성 및 캡슐화가 가능하다는 것을 장점이라 볼 수 있을 것 같다.


Profile picture
토대는 단단하게, 기술은 날렵하게 학습해 나가는 개발자 고상원입니다.