본문 바로가기

코딩

django models "Annotate, Aggregate, F, Q, Filter"

728x90
반응형

Django ORM의 annotate()는 쿼리셋에 새로운 계산 필드를 추가할 때 사용되는 메서드다. 이 메서드를 사용하면 기존 데이터베이스 필드와 함께 집계 함수나 계산된 값 등을 포함한 추가적인 데이터를 반환할 수 있다.

주요 특징

  1. 기존 쿼리셋에 새로운 필드(가상 필드)를 추가함.
  2. Aggregate와 함께 주로 사용되며, 그룹화된 데이터를 계산함.
  3. 새로운 필드는 쿼리셋의 각 개체에 추가됨.

사용 예시

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 []>

주의 사항

  1. Chaining:
    • filter()는 체이닝 가능하며, 체이닝할수록 조건이 추가로 적용됨.
products = Product.objects.filter(category="Electronics").filter(price__lt=500)
  1. Lazy Evaluation:
    • filter()는 실행 즉시 쿼리를 수행하지 않고, 데이터가 실제로 필요할 때 쿼리를 수행.
    • 효율적으로 사용할 수 있지만, 지나친 중복 호출을 피해야 함.
  2. 복잡한 조건:
    • 복잡한 논리 조건은 반드시 Q 객체와 함께 사용.

Django의 filter()는 데이터베이스 쿼리를 간결하고 직관적으로 작성할 수 있게 도와주는 강력한 도구다.

 

 

728x90
반응형