annotate() 메서드와 가변 키워드 인자

annotate() 메서드는 Django 쿼리셋에서 사용되는 함수 중 하나로, 데이터베이스에서 집계된 값을 추가하는 데 사용됩니다. annotate() 메서드를 사용하면 원하는 필드 값을 가져오고 그 값을 기반으로 새로운 필드를 생성할 수 있습니다.

annotate(aggregate_expression, ...)
  • aggregate_expression: 필드 값을 계산하기 위한 집계 식을 지정합니다. 일반적으로 Django의 django.db.models 모듈에 있는 집계 함수들을 사용합니다. 예를 들어, Count(), Sum(), Avg(), Min(), Max() 등이 있습니다.

annotate() 메서드는 쿼리셋의 결과에 대해 각 필드 값에 대한 집계를 수행하고, 결과에 추가된 필드를 포함한 새로운 쿼리셋을 반환합니다. 이를 통해 집계된 값을 활용할 수 있습니다.

Book 모델이 있다고 가정하고, 이 모델은 다음과 같은 필드가 있다고 가정하겠습니다.(title, author, pages)
이때 각 저자가 쓴 책들의 총 페이지 수를 계산한다면 아래처럼 사용할 수 있습니다.

from django.db.models import Sum  # 집계 함수

total_pages_by_author = Book.objects.values("author").annotate(Sum("pages"))

이러면 각 저자별로 책들의 총 페이지 수를 계산하고 그 결과를 pages__sum이라는 이름의 필드로 추가합니다. 그러면 각 저자의 이름과 그 저자의 책들의 총 페이지 수를 담은 딕셔너리의 쿼리셋을 리턴합니다.

리턴되는 쿼리셋의 예시는 아래와 같습니다.

total_pages_by_author = [
    {
        'author': 1,   # 작가1의 id
        'pages__sum': 250,  # 작가1이 쓴 책들의 페이지 수 합산
    },
    {
        'author': 2,   # 작가2의 id
        'pages__sum': 400,  # 작가2가 쓴 책들의 페이지 수 합산
    }
]

만약 pages__sum이라는 필드명이 아닌 사용자가 정의한 필드명으로 구현하고 싶다면 아래 방식대로 구현하면 됩니다.

annotate(field_name=aggregate_expression)
  • field_name: 생성된 필드의 이름을 지정합니다.

from django.db.models import Sum

total_pages_by_author = Book.objects.values("author").annotate(total_pages=Sum("pages"))

이러면 리턴값에 추가되는 필드명이 total_pages가 됩니다.

리턴되는 쿼리셋의 예시는 아래와 같습니다.

total_pages_by_author = [
    {
        'author': 1,   # 작가1의 id
        'total_pages': 250,  # 작가1이 쓴 책들의 페이지 수 합산
    },
    {
        'author': 2,   # 작가2의 id
        'total_pages': 400,  # 작가2가 쓴 책들의 페이지 수 합산
    }
]

가변 키워드 인자

이 annotate() 함수를 공부하면서 의아한 점이 생겼습니다. anootate() 함수의 field_name은 어떤 인자인지가 궁금해졌습니다. 키워드 인자도 아니고 위치 인자도 아니고 지정한 이름에 따라 바뀌는 인자가 무엇이지 찾아보며 알게 된 결론은 "가변 키워드 인자"였습니다.

 

참고로 아래 두 링크를 읽고 오시면 다음 내용이 더 이해가 잘 되실겁니다.

위치 인자와 키워드 인자 : https://yesaroun.tistory.com/entry/Python-%EC%9C%84%EC%B9%98-%EC%9D%B8%EC%9E%90-%ED%82%A4%EC%9B%8C%EB%93%9C-%EC%9D%B8%EC%9E%90

 

Python) 위치 인자, 키워드 인자

파이썬에서 함수를 호출할 때, 인자(argument)를 전달하는 방법에는 두 가지가 있습니다. 위치인자(Positional Arguments)와 키워드 인자(Keyword Arguments)로 나뉩니다. 1. 위치 인자 (Positional Arguments) 위치 인

yesaroun.tistory.com

django에서 *args, **kwargs : https://yesaroun.tistory.com/entry/django%EC%97%90%EC%84%9C-args-kwargs

 

django에서 *args, **kwargs

Django와 같은 Python 기반 프레임워크에서 *args와 **kwargs는 함수나 메소드에 임의의 개수의 인자를 전달하는데 사용되는 문법입니다. *args: *args는 임의의 개수의 위치 인자를 함수나 메소드로 전달

yesaroun.tistory.com

 

annotate()는 키워드 인자를 받아서 새로운 필드 이름으로 사용하는 "키워드 인자 패킹"이라는 Python의 기능을 사용합니다.

아래의 예시가 가변 키워드 인자를 사용하는 예시입니다.

def func(**kwargs):
    for key, value in kwargs.items():
        print(f"{key} = {value}")

func(a=1, b=2)
# a = 1
# b = 2

이 예시는 단순하게 **kwargs 인자를 설명하는 예시일 수 있습니다. 하지만 이 예시 대로 annotate() 메서드의 가변 키워드 인자도 동일하게 동작합니다.

아래는 annotate()에서 사용되는 가변 키워드 인자 개념을 보기 쉽게 표현한 annotate_func() 코드입니다.

def annotate_func(**kwargs):
    # 이 경우 kwargs = {"total_pages": Sum("pages")}

    aggregates = kwargs  # 집계 표현식을 저장하는 딕셔너리

    for field, aggregate_expr in aggregates.items():
        # 각 키와 값을 출력합니다.
        print(f"필드명: {field}, 집계 표현식: {aggregate_expr}")

annotate_func(total_pages="Sum('pages')")
# 필드명: total_pages, 집계 표현식: Sum('pages')

만약 더 django의 annotate() 메소드 코드를 보고 싶으면 아래 코드를 확인해 주세요.
django 코드 링크 : https://github.com/django/django/blob/3.2/django/db/models/query.py

'Python > Django' 카테고리의 다른 글

Django에서의 Transactions  (0) 2023.08.26
values_list()  (0) 2023.08.09
django에서 *args, **kwargs  (0) 2023.07.25
get_user_model()  (0) 2023.07.22
django 템플릿 <script>태그  (0) 2023.07.08