- Published on
Django ORM에서 aggregate, Subquery, OuterRef, Coalesce 쉽게 이해하기
- Authors
- Name
- hongreat
- ✉️hongreat95@gmail.com
Django ORM에서 aggregate, Subquery, OuterRef, Coalesce 을 사용하면 어려운 쿼리문을 보다 쉽게 쿼리할 수 있습니다.
하지만 Django ORM 과 SQL 등의 Query 에 익숙치 않다면, 이마저도 사용에 어려움을 느끼기 마련입니다.
이 함수(클래스)들은 집계와 참조를 통해 데이터를 가공할 수 있습니다.
각 코드와 결과 값(타입 포함) 을 잘 생각하면서 사용해야 온전한 목적에 맞게 사용할 수 있는데, 차례대로 살펴보겠습니다.
1. Aggregate
개요: aggregate()
는 Django ORM에서 모델 필드의 값에 대해 특정 집계 함수(예: 합계, 평균, 최대, 최소 등)를 적용하고 결과를 반환하는 메서드입니다.
사용법: 이 메서드는 쿼리셋에 대한 집계 연산을 수행하며, 결과는 딕셔너리 형태로 반환됩니다.
예시: 모든 Employee
객체의 평균 급여를 계산합니다.
from django.db.models import Avg
from myapp.models import Employee
average_salary = Employee.objects.aggregate(average_salary=Avg('salary'))
2. Subquery와 OuterRef
2.1. Subquery
개요:Subquery
는 한 쿼리 안에서 다른 쿼리를 실행하는 방법으로 사용됩니다.이는 다른 쿼리셋의 결과를 현재 쿼리셋의 필터링, 집계 또는 값으로 사용할 때 유용합니다.
2.2. OuterRef
개요: OuterRef
는 외부 쿼리(메인 쿼리)의 필드를 내부 쿼리(서브쿼리)에서 참조하는 데 사용됩니다.
사용법: Subquery
와 OuterRef
를 함께 사용하여 복잡한 쿼리를 구성할 수 있습니다.
이 방법은 특히 관계형 데이터에서 관련된 모델 간의 데이터를 처리할 때 유용합니다.
예시: ParentModel
의 각 인스턴스에 대해 연관된 ChildModel
인스턴스들의 value
합계를 계산합니다.
from django.db.models import Subquery, OuterRef, Sum
from myapp.models import ParentModel, ChildModel
# ChildModel의 'value' 필드에 대한 합계를 계산하는 서브쿼리 생성
sum_subquery = Subquery( ChildModel.objects.filter(parent_id=OuterRef('pk')).values('parent_id') .annotate(total_value=Sum('value')) .values('total_value')[:1] ) # ParentModel의 각 인스턴스에 서브쿼리 결과를 포함
parent_queryset = ParentModel.objects.annotate( total_value_of_child=sum_subquery ) # ParentModel 전체에 대한 총 합계를 계산
total_sum = parent_queryset.aggregate(total_sum_of_all_children=Sum('total_value_of_child'))['total_sum_of_all_children']
3. Coalesce
개요: Coalesce
는 여러 컬럼이나 표현식 중에서 NULL
이 아닌 첫 번째 값을 반환하는 데이터베이스 함수입니다.
Django ORM에서도 Coalesce
함수를 제공하여, 여러 필드 중 NULL
이 아닌 첫 번째 값을 선택할 수 있습니다.
사용법: 이 함수는 필드 중 하나 이상이 NULL
일 가능성이 있을 때 유용합니다.
특히, 선택적 필드나 기본값이 설정되지 않은 필드에서 NULL
값을 기본값이나 다른 필드의 값으로 대체하고자 할 때 사용됩니다.
예시: field1
과 field2
중 첫 번째 NULL이 아닌 값을 반환합니다.
from django.db.models import Coalesce
from myapp.models import MyModel
queryset = MyModel.objects.annotate( non_null_field=Coalesce('field1', 'field2') )
예시2 : UserProfile
모델에서 status
필드에 따라 다른 필드를 우선적으로 선택합니다.
from django.db.models import Case, When, Value, CharField, Coalesce
from .models import UserProfile
user_contact_info = UserProfile.objects.annotate(
preferred_contact=Case(
When(status='verified', then=Coalesce('email', 'phone', 'nickname')),
default=Coalesce('phone', 'email', 'nickname'),
output_field=CharField()
)
).values('preferred_contact')
# 결과를 조회합니다.
for user in user_contact_info:
print(user['preferred_contact'])