Django project # 1

minch·2021년 8월 7일
1

Django

목록 보기
13/16
post-thumbnail

Blocker

제품에서 필터별 정렬 기능을 구현하기 위하여,

order_by() 메서드를 이용하여 처리하였다.

products/models.py

...
class Product(models.Model):
    name                = models.CharField(max_length=45)

class Option(models.Model):
    size    = models.PositiveIntegerField()
    price   = models.DecimalField(max_digits = 12, decimal_places = 2)
    product = models.ForeignKey('Product', on_delete = models.CASCADE)

모델링을 살펴보면,
한 제품이 여러 사이즈와 여러 가격을 갖고있기 때문에
product에 참조키를 가진 option 테이블을 따로 만들어주었다.

id제품명
1아워 크림
2아워 샴푸
3아워 로션
4아워 스킨

idsizepriceproduct_id
110080001
2500450001
3100100002
4100150003
5100200004
>>> Product.objects.all().order_by('option__price')

이렇게 정렬을 하게 되면 product를 바라보는 모든 price를 참고하여 정렬하게 된다.

아워 샴푸(10000) - 아워 로션(15000) - 아워 스킨(20000) - 아워 크림(45000)

하지만, 가격이 여러 개인 것들 중 가장 낮은 가격을 제품 리스트에 표기를 하기로 하였다면

아워 샴푸(10000) - 아워 로션(15000) - 아워 스킨(20000) - 아워 크림(8000)??

위와 같은 방법으로 정렬하는 것에 어려움이 생긴다.

해결방법

그래서 사용한 방법이 annotate이다.

annotate?

annotate란, 필드 하나를 만들고 거기에 '어떤 내용' 을 채우게 만드는 것이다. 엑셀에서 컬럼 하나를 만드는 것과 같다고 보면 된다. 주로 Min, Max, Avg, Count등의 method와 함께 쓰인다.

다시 말해서, 아래의 테이블에

id제품명
1아워 크림
2아워 샴푸
3아워 로션
4아워 스킨

id제품명가격
1아워 크림8000
2아워 샴푸10000
3아워 로션15000
4아워 스킨20000

가격이라는 필드를 만들고, 제품을 가리키는 price들 중 가장 낮은 가격을 내용으로 채워놓는 것이다.

>>> from django.db.models import Min # 낮은 값을 찾아주는 django ORM 메서드
>>> products = Product.objects.all().annotate(price=Min('option__price'))
 # 위와 같은 모양을 가진 테이블을 생성
>>> products.order_by('price') # price 필드를 기준으로 정렬

이렇게 하면,

원하는대로 아워 크림(8000) - 아워 샴푸(10000) - 아워 로션(15000) - 아워 스킨(20000) 정렬이 된다.

vs aggregate?

annotate는 계산용 컬럼을 하나 추가하는 것이라면,
aggregate는 특정 컬럼 전체를 대상으로 계산하는 것과 같다. (합, 평균, 개수 등)

예를 들어 위에서 만든 products 가격의 평균을 구하고 싶으면 아래와 같이 하면 된다.

>> from django.db.models import Avg
>> products.aggregate(avg=Avg('price'))
{'avg': Decimal('13250.000000')}

참조
(http://raccoonyy.github.io/django-annotate-and-aggregate-like-as-excel/)

1개의 댓글

comment-user-thumbnail
2021년 8월 8일

👍🏼👍🏼👍🏼👍🏼👍🏼

답글 달기