Django ORM의 기본 동작 이해하기

Kangjik Kim·2025년 4월 14일
0

objects 매니저의 동작 방식

Django 모델의 objects 매니저를 사용할 때, .all()이 없어도 기본적으로 모든 객체를 대상으로 동작합니다.

예를 들어, 다음 두 쿼리는 동일합니다:

# 방법 1
Post.objects.all().annotate(comment_count=Count('comments'))

# 방법 2
Post.objects.annotate(comment_count=Count('comments'))

왜 이렇게 동작하나요?

  1. objects 매니저는 기본적으로 모델의 전체 QuerySet을 가리킵니다.
  2. 모든 QuerySet 메서드는 새로운 QuerySet을 반환합니다.
  3. .all()은 사실상 현재 QuerySet의 복사본을 반환하는 것이므로 생략 가능합니다.

실제 SQL 비교

두 방법 모두 동일한 SQL을 생성합니다:

SELECT
    "post".*,
    COUNT("comments"."id") as "comment_count"
FROM "post"
LEFT OUTER JOIN "comments" ON "post"."id" = "comments"."post_id"
GROUP BY "post"."id";

다른 메서드들과의 비교

# 전체 객체 대상
Post.objects.annotate(...)  # 모든 Post 대상
Post.objects.all().annotate(...)  # 위와 동일

# 필터링된 객체 대상
Post.objects.filter(status='ACTIVE').annotate(...)  # 활성 Post만 대상

예제

# 불필요한 .all() 사용
posts = (
    Post.objects
        .all()  # 불필요
        .annotate(comment_count=Count('comments'))
        .filter(comment_count__gt=5)
)

# 최적화된 코드
posts = (
    Post.objects
        .annotate(comment_count=Count('comments'))
        .filter(comment_count__gt=5)
)

주의사항

.all()이 실제로 필요한 경우가 있습니다:

  1. QuerySet을 복사하고 싶을 때
original_qs = Post.objects.filter(status='ACTIVE')
new_qs = original_qs.all()  # 새로운 QuerySet 생성
  1. 캐시된 QuerySet을 초기화하고 싶을 때
posts = Post.objects.all()
# ... 일부 작업 수행 ...
posts = posts.all()  # QuerySet 초기화

이처럼 Django ORM에서는 objects 매니저 자체가 이미 전체 객체에 대한 QuerySet을 의미하므로, .all()은 대부분의 경우 생략 가능합니다.

0개의 댓글