쿼리셋에 있는 각 항목에 대해 계산된 필드(집계된 값을 포함할 수 있음)를 추가.
기본적으로 각 객체(또는 그룹)에 대해 추가 정보를 "주석" 형태로 부여하며, 이를 통해 반환되는 각 객체가 추가적인 데이터를 포함하게 됨.
즉, 쿼리셋의 구조를 변경하지 않고 각 객체에 추가 정보를 부여.
authors = Author.objects.annotate(num_books=Count('books'))
전체 쿼리셋에 대한 집계 연산을 수행하고, 그 결과로 단일 값(또는 값의 집합)을 반환
즉, 원래의 객체 리스트를 반환하지 않고, 집계된 결과만을 반환
result = Book.objects.aggregate(average_pages=Avg('num_pages'))
외래 키(ForeignKey)나 일대일(OneToOne) 관계를 통한 SQL JOIN을 수행하고, 연결된 객체를 한 번의 쿼리로 데이터베이스로부터 불러옴.
이는 "하나의 큰 쿼리"를 사용하여 필요한 모든 관련 데이터를 가져오는 방식으로, 주로 성능 최적화에 유용.
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
# Author 객체를 포함하여 Book 객체 가져오기
books = Book.objects.prefetch_related('authors').all()
for book in books:
print(book.title)
for author in book.authors.all():
print(author.name)
다대다(ManyToMany) 관계나 "역" 외래 키 관계에서 사용.
별도의 쿼리를 수행하여 관련 객체를 가져오고, Python 코드 내에서 이를 합치는 방식으로 작동.
이는 여러 관계가 있는 객체를 효율적으로 불러올 때 사용하며, 여러 개의 쿼리가 발생하긴 하지만 전체적인 성능 최적화에 도움을 줌.
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
# Author 객체를 포함하여 Book 객체 가져오기
books = Book.objects.prefetch_related('authors').all()
for book in books:
print(book.title)
for author in book.authors.all():
print(author.name)
하나의 쿼리셋이 다른 쿼리셋 내부에서 쿼리로 사용되는 경우에 적용
class School(models.Model):
name = models.CharField(max_length=100)
class Student(models.Model):
name = models.CharField(max_length=100)
school = models.ForeignKey(School, on_delete=models.CASCADE)
grade = models.IntegerField()
lowest_grade_per_school = Student.objects.filter(
school=OuterRef('pk')
).values('school').annotate(
min_grade=Min('grade')
).values('min_grade')
schools_with_lowest_grade = School.objects.annotate(
lowest_grade=Subquery(lowest_grade_per_school)
)
특정 객체들에 대해서 추가적인 정보가 필요하다.
filter(조건).annotate(키=벨류)
특정 객체들을 필터링해야하는데 필터링을 위한 정보가 존재하지 않아 새로 추가해야한다.
annotate(키=벨류).filter(조건)
각 사용자별로 주문한 수를 구하고 싶다.
user_total_orders = User.objects.annotate(total_amount=Count('orders'))
각 사용자별로 주문한 금액의 총합을 계산하고 싶다.
user_total_orders = User.objects.annotate(total_amount=Sum('orders__price'))