0. ORM사용하기 위한 사전 작업
articles/models.py
from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator
class Product(models.Model):
CATEGORY_CHOICES = (
("F", "Fruit"),
("V", "Vegetable"),
("M", "Meat"),
("O", "Other"),
)
name = models.CharField(max_length=100)
price = models.PositiveIntegerField()
quantity = models.PositiveIntegerField()
category = models.CharField(max_length=1, choices=CATEGORY_CHOICES)
def __str__(self):
return self.name
django seed로 생성
python manage.py seed products --number=30
Django ORM (심화)
- 기본적인 ORM 외에도 다양한 비지니스 상황에 맞는 쿼리가 필요
- Django의 ORM은 대부분의 쿼리가 가능하도록 설계됨
- 값을 가져와서 Python으로 조작해도 되지만 Database에서 조작한 후 가져오는것이 필요한 경우가 있음
query문 작동 확인은 shell_plus에서!
01. Q() 를 이용해서 여러 조건 연결하기
- 여러 조건에 해당하는 ORM이 필요하다면 Q 객체를 사용
- Q 는 조건을 정의하는 객체로 논리적 OR 조건을 만들거나 여러개의 조건을 결합해서 SQL의 WHERE 절에 해당하는 기능을 온전히 활용할 수 있음
- & : and, | : or, ~ : not 연산자 활용 가능
# 가격이 15000보다 크거나 수량이 3000보다 적은 제품들을 조회
Product.objects.filter(
Q(price__gt=15000) | Q(quantity__lt=3000)
)
# 가격이 10000보다 크고 수량이 2000보다 적은 제품들을 조회
Product.objects.filter(
Q(price__gt=10000) & Q(quantity__lt=2000)
)
02. F() 를 이용해서 필드값 가져오기
- F() 는 쿼리를 작성할 때 이전의 필드 값에 의존하는 작업을 도와줌
- 주로 필드의 값을 가져오거나 업데이트해서 값을 참조하는데 사용
- python 메모리로 값을 가져오지 않고 필요한 작업을 데이터베이스에서 수행할 수 있음
# 모든 프로덕트의 가격을 1000원 인상
Product.objects.update(price = F('price') + 1000)
03. annotate() 를 사용해서 추가 정보 제공하기
https://docs.djangoproject.com/en/4.2/ref/models/querysets/#annotate
- annotate == 주석을달다
- 조회하는 쿼리셋 각각에 추가적인 정보(데이터)를 제공하는데 사용
# 각 프로덕트 별 total_price를 추가로 구성해서 조회(total_price = price * quantity)
products = Product.objects.annotate(
total_price=F('price') * F('quantity')
)
03.aggregate() 를 사용해서 쿼리하기
- aggregate == 종합/집약하다
- 조회하는 쿼리셋 전체에 대해 결과를 집계/집약
- 주로 집계 함수(Avg, Sum, Count 등)와 많이 사용
# 전체 프로덕트의 평균 가격
Product.objects.aggregate(Avg('price'))
# {'price__avg': 14627.76}
# 컬럼 이름을 주고 싶을 때
Product.objects.aggregate(my_avg = Avg('price'))
# {'my_avg': 14627.76}
04. Group By 적용하기
# 이렇게 쓰면 전체 데이터 조회랑 같음
Product.objects.aggregate(Count('category'))
# {'category__count': 30}
따라서 세가지 방법이 있음.
- (Recommend) Django에서 Group By는 아래의 두 단계를 이용해서 수행
# 내가 원하는 컬럼만 뽑기
Product.objects.values('category')
# <QuerySet [{'category': 'M'}, {'category': 'O'},
# {'category': 'V'}, {'category': 'M'}, ...
# {'category': 'F'}, '...(remaining elements truncated)...']>
# annotate() 로 묶어서 Group By를 수행
Product.objects.values('category').annotate(category_count = Count('category'))
# {'category': 'F', 'category__count': 15},
# {'category': 'M', 'category__count': 15},
# {'category': 'O', 'category__count': 15},
# {'category': 'V', 'category__count': 5}
- Raw()를 이용해서 직접 SQL문을 입력하기 (Django ORM으로 하기 어려운 쿼리문이라면)
categories_count = Product.objects.raw(
'''
SELECT "id", "category", COUNT("category") AS "category_count"
FROM "products_product"
GROUP BY "category"
'''
)
for each in categories_count:
print(each.category_count, each.category)
# 15 F
# 15 M
# 15 O
# 5 V
- 직접 Database Connection을 만들고 쿼리하기 (마찬가지로 Django ORM으로 하기 어려운 쿼리문이라면)
from django.db import connection
sql_query = '''
SELECT "category", COUNT("category") AS "category_count"
FROM "products_product"
GROUP BY "category"
'''
cursor = connection.cursor()
cursor.execute(sql_query)
result = cursor.fetchall()
print(result)
# [('F', 15), ('M', 15), ('O', 15), ('V', 5)]
작성하는 대부분의 쿼리는 Django ORM 선에서 해결됨으로 첫번째 방법을 사용하자!
'Django' 카테고리의 다른 글
Redis (1) | 2024.08.30 |
---|---|
Django ORM 최적화 (0) | 2024.08.30 |
JSON Web Token, JWT (0) | 2024.08.30 |
Serializer 활용하기 (0) | 2024.08.29 |
Relationship과 DRF(with. particular seed) (0) | 2024.08.29 |