Django Manager

Nam Eun-Ji·2022년 4월 10일

참고
Django Documentation - Managers

장고 orm을 사용할 때 늘 사용했던 건데 이게 뭘까라고 생각해보지는 않았던 것 같다.
아래 코드 부분에 objects 부분이다.

# ex
user = User.objects.get(id=1)
  • 모든 model class에 대해 objects라는 Manager(django.db.models.Manager) 객체를 자동으로 추가한다. 때문에 별도의 Manager추가 없이 쿼리셋을 사용할 수 있다.
  • Django는 Manager를 통해 데이터베이스와 통신하는 것이다.
  • 모든 Model은 하나 이상의 Manager를 가지게 된다.






change Manager names

from django.db import models

class Person(models.Model):
    #...
    people = models.Manager()
user.people.all()






Custom managers

그럼 왜 manager 객체를 왜 custom하는걸까?
django 문서에 따르면

  • extra Manager method를 추가하기 위해
  • Manager가 반환하는 initial QuerySet을 수정하기 위해

Adding extra Manager method

  • 모델에 테이블 단위(table-level)로 기능을 추가하고 싶을 때 사용 (집계 쿼리 등)
  • 행 단위(row-level)의 경우(모델 객체의 단일 인스턴스에서 작동하는 함수) 기능을 작성할 때 Model의 메서드를 사용하는 것이 좋다.
  • Manager 메서드는 QuerySet, int, string, dict 등의 형태로 리턴 가능(즉, 꼭 쿼리셋이 아닌 원하는 모든 것을 반환할 수 있다.)
  • Ex)
    아래 코드를 보면 num_responses 속성이 추가된 OpinionPoll 객체의 쿼리셋을 OpinionPoll.objects.with_counts()을 통해 가져올 수 있다.
from django.db import models
from django.db.models.functions import Coalesce

class PollManager(models.Manager):
    def with_counts(self):
        return self.annotate(
            num_responses=Coalesce(models.Count("response"), 0)
        )

# 여론조사 - 질문
class OpinionPoll(models.Model):
    question = models.CharField(max_length=200)
    objects = PollManager()

# 여론조사 - 답변
class Response(models.Model):
    poll = models.ForeignKey(OpinionPoll, on_delete=models.CASCADE)
    # ...

table level? row level?

아래 내용은 내가 이해한 것을 작성한 것이라 틀릴 수 있다.

  • row level은 테이블에서 1줄, 즉 모델 인스턴스 1개를 말하며, row-level단에서 무언가 재사용하고 싶은 메소드를 만들고 싶다면, 모델 이하에 메소드를 생성하면 된다.
  • table level은 그와 반대로 테이블 기준으로 복수개의 row를 뽑아내는 경우를 말한다.
# table-level
class ActiveUserManager(models.Manager):
	def get_queryset(self):
    	return superr().get_queryset().filter(is_active=True)

class User(models.Model):
	first_name = models.CharField()
    last_name = models.CharField()
    
    active_user = ActiveUserManager()
    
    # row-level
    def get_fullname(self):
    	return self.first_name + self.last_name



Modifying a manager’s initial QuerySet

  • Manager의 기본 QuerySet은 해당 Model의 모든 데이터를 반환한다.
  • 초기의 Queryset에 Manager를 사용하여 필터링 가능
  • Ex)
    Book.objects.all()은 모든 Book에 대해 리턴할 것이다.
from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=50)
  • 아래처럼 get_queryset()을 재정의하여 Manager의 기본 쿼리셋을 재정의할 수 있다.
    • objects : 기본 Manager - 즉 모든 Book 객체를 가져온다.
    • dahl_objects : author가 Roald Dahl인 Book 객체만 가져온다.
    • Extra Manager 메소드와 다르게 get_queryset메소드는 반드시 QuerySet을 리턴해야 한다.
# First, define the Manager subclass.
class DahlBookManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(author='Roald Dahl')

# Then hook it into the Book model explicitly.
class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=50)

    objects = models.Manager() # The default manager.
    dahl_objects = DahlBookManager() # The Dahl-specific manager.
  • 쿼리셋을 리턴하므로 filter 나 exclude, count 등 모든 표준 QuerySet의 기능을 사용할 수 있다.
Book.dahl_objects.filter(title='Matilda')
Book.dahl_objects.count()
profile
한 줄 소개가 자연스러워지는 그날까지

0개의 댓글