[DRF] ORM 심화 2

집중맞은 도둑력·2024년 5월 28일

웹 개발

목록 보기
13/14
post-thumbnail

0. 🔖 목차


  1. ORM 심화 2
    1-1. ORM에서의 GROUP_BY와 집계 함수들
    1-2. ORM에서의 JOIN
    1-3. ORM에서의 서브쿼리
    1-4. ORM으로 생각하기

1. ORM 심화 2


1-1. ORM에서의 GROUP_BY와 집계 함수들

Annotate

쿼리셋에 있는 각 항목에 대해 계산된 필드(집계된 값을 포함할 수 있음)를 추가.

기본적으로 각 객체(또는 그룹)에 대해 추가 정보를 "주석" 형태로 부여하며, 이를 통해 반환되는 각 객체가 추가적인 데이터를 포함하게 됨.

즉, 쿼리셋의 구조를 변경하지 않고 각 객체에 추가 정보를 부여.

authors = Author.objects.annotate(num_books=Count('books'))

Aggregate

전체 쿼리셋에 대한 집계 연산을 수행하고, 그 결과로 단일 값(또는 값의 집합)을 반환

즉, 원래의 객체 리스트를 반환하지 않고, 집계된 결과만을 반환

result = Book.objects.aggregate(average_pages=Avg('num_pages'))

1-2. ORM에서의 JOIN

외래 키(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)

1-3. ORM에서의 서브쿼리

Subquery와 OuterRef

하나의 쿼리셋이 다른 쿼리셋 내부에서 쿼리로 사용되는 경우에 적용

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)
)

1-4. ORM으로 생각하기

특정 객체들에 대해서 추가적인 정보가 필요하다.

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'))
profile
틀린_내용이_있다면_말해주세요.

0개의 댓글