728x90
반응형
Django ORM의 annotate()는 쿼리셋에 새로운 계산 필드를 추가할 때 사용되는 메서드다. 이 메서드를 사용하면 기존 데이터베이스 필드와 함께 집계 함수나 계산된 값 등을 포함한 추가적인 데이터를 반환할 수 있다.
주요 특징
- 기존 쿼리셋에 새로운 필드(가상 필드)를 추가함.
- Aggregate와 함께 주로 사용되며, 그룹화된 데이터를 계산함.
- 새로운 필드는 쿼리셋의 각 개체에 추가됨.
사용 예시
1. 기본 사용법
from django.db.models import Count
from myapp.models import Author, Book
# 각 작가가 쓴 책의 수를 계산
authors = Author.objects.annotate(book_count=Count('book'))
for author in authors:
print(author.name, author.book_count)
- book_count: 작가별로 작성한 책의 수를 계산한 필드.
- Count('book'): Book 모델과 Author 모델의 관계를 기반으로 책 수를 셈.
2. 조건부 필드 계산
from django.db.models import Sum, F, Q
# 각 작가가 작성한 특정 조건을 만족하는 책의 수를 계산
authors = Author.objects.annotate(
total_pages=Sum('book__pages', filter=Q(book__genre='Fiction'))
)
for author in authors:
print(author.name, author.total_pages)
- 조건부 계산: 특정 조건(장르가 'Fiction')에 해당하는 책의 총 페이지 수 계산.
3. 계산된 값 사용
from django.db.models import F
# 판매 수익 계산
books = Book.objects.annotate(total_revenue=F('price') * F('sold_copies'))
for book in books:
print(book.title, book.total_revenue)
- F 객체: 필드 값을 참조하여 계산.
4. 그룹화와 함께 사용
from django.db.models import Avg
# 작가별 평균 책 페이지 수
authors = Author.objects.annotate(avg_pages=Avg('book__pages'))
for author in authors:
print(author.name, author.avg_pages)
- Avg('book__pages'): 각 작가의 책 페이지 수 평균 계산.
Annotate vs Aggregate
| 특징 | Annotate | Aggregate |
| 목적 | 각 객체별 계산된 필드 추가 | 전체 데이터에 대해 단일 값을 계산 |
| 반환 | 새로운 필드가 포함된 쿼리셋 | 계산된 단일 값 또는 사전 |
| 사용 예시 | Author.objects.annotate(book_count=Count('book')) | Book.objects.aggregate(total_books=Count('id')) |
유용한 Aggregation 함수
- Count: 개수 계산
- Sum: 합계 계산
- Avg: 평균 계산
- Max: 최대값 계산
- Min: 최소값 계산
annotate()는 데이터 처리에 강력한 도구로, 조건부 집계나 계산이 필요한 상황에서 효과적으로 사용된다.
Django ORM에서 F와 Q 객체는 데이터베이스 쿼리를 동적으로 생성하고, 더 복잡한 조건을 표현하거나 필드 값을 직접 참조할 때 사용된다.
1. F 객체
- 역할:
- 데이터베이스 필드 값을 참조하여 연산하거나 비교할 때 사용.
- 동일한 모델 내의 다른 필드 간 계산을 처리하거나 값을 갱신할 때 유용.
- 사용 예시:
from django.db.models import F
# Example 1: 두 필드 비교
from myapp.models import Product
products = Product.objects.filter(stock__lt=F('sold')) # 재고(stock)가 판매량(sold)보다 적은 상품.
# Example 2: 필드 값을 업데이트
Product.objects.update(price=F('price') * 1.1) # 모든 상품 가격에 10% 인상.
# Example 3: 필드 값 참조
orders = Order.objects.annotate(total_cost=F('quantity') * F('unit_price'))
for order in orders:
print(order.total_cost) # 계산된 값.
- 특징:
- 데이터베이스 내에서 직접 계산을 처리하므로 효율적이다.
- SQL로 변환 시 WHERE stock < sold 또는 SET price = price * 1.1과 같은 쿼리를 생성.
2. Q 객체
- 역할:
- 복잡한 쿼리 조건(특히 OR 조건이나 NOT 조건)을 생성.
- 기본적으로 filter()는 조건을 AND로 연결하지만, Q 객체를 사용하면 OR, NOT 같은 논리 연산자를 사용할 수 있다.
- 사용 예시:
from django.db.models import Q
# Example 1: OR 조건
customers = Customer.objects.filter(Q(age__lt=18) | Q(age__gt=60)) # 18세 미만 또는 60세 초과 고객.
# Example 2: AND 조건
items = Item.objects.filter(Q(price__gte=1000) & Q(stock__gte=10)) # 가격 ≥ 1000 AND 재고 ≥ 10.
# Example 3: NOT 조건
users = User.objects.filter(~Q(is_active=True)) # 비활성화된 사용자.
# Example 4: 다중 Q 객체
orders = Order.objects.filter(
Q(status='shipped') | (Q(status='processing') & Q(priority='high'))
)
- 특징:
- | (OR), & (AND), ~ (NOT) 같은 연산자를 사용해 논리 조건을 표현.
- SQL로 변환 시 WHERE age < 18 OR age > 60 같은 쿼리를 생성.
F와 Q 객체 비교
| 특징 | F 객체 | Q 객체 |
| 목적 | 필드 값을 참조하거나 계산에 사용 | 복잡한 조건을 표현 (OR, NOT 등) |
| 사용 위치 | filter(), annotate(), update() 등 | filter(), exclude() 등 |
| SQL 변환 | 필드 간 비교 및 계산 (SET, WHERE) | 조건식 표현 (WHERE, OR, AND) |
예제: F와 Q 함께 사용
from django.db.models import F, Q
# Example: 10% 이상 할인된 상품 또는 재고가 판매량보다 많은 상품
products = Product.objects.filter(
Q(discount__gte=F('price') * 0.1) | Q(stock__gt=F('sold'))
)
- 여기서 F('price') * 0.1로 할인율을 계산하고, Q를 사용해 조건을 결합.
정리
- F 객체: 필드 값을 참조하거나 계산할 때 사용.
- Q 객체: 복잡한 조건을 논리적으로 결합할 때 사용.
이를 활용하면 Django ORM으로 효율적이고 유연한 쿼리를 작성할 수 있다.
Django ORM에서 filter()는 특정 조건을 만족하는 데이터만 쿼리셋으로 반환할 때 사용하는 메서드다. SQL의 WHERE 절에 해당하며, 조건에 따라 데이터를 필터링한다.
기본 문법
Model.objects.filter(조건1, 조건2, ...)
- 조건: 필드 이름과 조회 조건을 키워드 인수로 전달.
- 반환값: 조건에 맞는 객체들의 쿼리셋.
사용 예제
1. 단순 조건
from myapp.models import Product
# Example 1: 특정 필드 값과 일치하는 객체 조회
products = Product.objects.filter(name="Laptop")
# SQL: SELECT * FROM product WHERE name = 'Laptop';
# Example 2: 특정 필드 값이 다른 객체 조회
products = Product.objects.filter(price__gt=1000) # 가격이 1000보다 큰 상품
# SQL: SELECT * FROM product WHERE price > 1000;
2. 여러 조건
# AND 조건
products = Product.objects.filter(category="Electronics", price__lt=500)
# SQL: SELECT * FROM product WHERE category = 'Electronics' AND price < 500;
# OR 조건 (Q 객체 사용)
from django.db.models import Q
products = Product.objects.filter(Q(category="Electronics") | Q(price__lt=500))
# SQL: SELECT * FROM product WHERE category = 'Electronics' OR price < 500;
3. 관계 모델 필터링
from myapp.models import Author, Book
# ForeignKey 관계에서 필터링
books = Book.objects.filter(author__name="John Doe")
# SQL: SELECT * FROM book WHERE author.name = 'John Doe';
# ManyToManyField 관계에서 필터링
authors = Author.objects.filter(books__title="Django for Beginners")
# SQL: SELECT * FROM author INNER JOIN book ON ... WHERE book.title = 'Django for Beginners';
4. Negation (NOT 조건)
# NOT 조건 (Q 객체의 ~ 사용)
from django.db.models import Q
products = Product.objects.filter(~Q(category="Electronics"))
# SQL: SELECT * FROM product WHERE NOT (category = 'Electronics');
지원하는 조회 조건
Django에서 filter()는 다양한 조건을 지원한다. 주요 조건은 다음과 같다.
| 조건 | 설명 | 예제 | SQL |
| field=value | 특정 값과 일치 | name="Laptop" | WHERE name = 'Laptop' |
| field__exact=value | 특정 값과 정확히 일치 | name__exact="Laptop" | WHERE name = 'Laptop' |
| field__iexact=value | 대소문자 구분 없이 일치 | name__iexact="laptop" | WHERE name ILIKE 'laptop' |
| field__contains=value | 특정 값을 포함 | name__contains="top" | WHERE name LIKE '%top%' |
| field__icontains=value | 대소문자 구분 없이 포함 | name__icontains="TOP" | WHERE name ILIKE '%TOP%' |
| field__in=[values] | 값 목록 중 하나와 일치 | category__in=["A", "B"] | WHERE category IN ('A', 'B') |
| field__gt=value | 값보다 큰 경우 | price__gt=1000 | WHERE price > 1000 |
| field__gte=value | 값보다 크거나 같은 경우 | price__gte=1000 | WHERE price >= 1000 |
| field__lt=value | 값보다 작은 경우 | price__lt=1000 | WHERE price < 1000 |
| field__lte=value | 값보다 작거나 같은 경우 | price__lte=1000 | WHERE price <= 1000 |
| field__startswith=value | 특정 값으로 시작 | name__startswith="Lap" | WHERE name LIKE 'Lap%' |
| field__istartswith=value | 대소문자 구분 없이 시작 | name__istartswith="lap" | WHERE name ILIKE 'lap%' |
| field__endswith=value | 특정 값으로 끝남 | name__endswith="top" | WHERE name LIKE '%top' |
| field__iendswith=value | 대소문자 구분 없이 끝남 | name__iendswith="TOP" | WHERE name ILIKE '%TOP' |
| field__range=(start, end) | 특정 범위 내 값 | price__range=(100, 500) | WHERE price BETWEEN 100 AND 500 |
| field__isnull=True/False | 값이 NULL인지 여부 | stock__isnull=True | WHERE stock IS NULL |
결과 반환
- filter()는 조건에 맞는 객체들의 쿼리셋을 반환.
- 결과가 없으면 빈 쿼리셋 반환.
results = Model.objects.filter(name="Nonexistent")
print(results) # <QuerySet []>
주의 사항
- Chaining:
- filter()는 체이닝 가능하며, 체이닝할수록 조건이 추가로 적용됨.
products = Product.objects.filter(category="Electronics").filter(price__lt=500)
- Lazy Evaluation:
- filter()는 실행 즉시 쿼리를 수행하지 않고, 데이터가 실제로 필요할 때 쿼리를 수행.
- 효율적으로 사용할 수 있지만, 지나친 중복 호출을 피해야 함.
- 복잡한 조건:
- 복잡한 논리 조건은 반드시 Q 객체와 함께 사용.
Django의 filter()는 데이터베이스 쿼리를 간결하고 직관적으로 작성할 수 있게 도와주는 강력한 도구다.

728x90
반응형
'코딩' 카테고리의 다른 글
| AI 시대에 코딩을 배워야 하는 이유 (2) | 2025.01.05 |
|---|---|
| 늙어야 더 잘한다: 인공지능 코딩 부트캠프 (2) | 2025.01.05 |
| 서버 OS 시장점유율 1위는 리눅스 그리고 우분투 (0) | 2025.01.03 |
| ChatGPT 로 Python 코딩하기 - 아파트 매매 호가 수집 (1) | 2025.01.01 |
| Django 웹 프레임워크 "Hello World" (0) | 2025.01.01 |