Django project # 3

minch·2021년 8월 12일
1

Django

목록 보기
15/16
post-thumbnail

장바구니 기능 구현

user가 장바구니에 담은 정보를 보여주는 기능을 구현하기 위해,

get 메소드를 이용하여 아래와 같이 작업하였다.

...
FREE_SHIPPING = 20000
...
class CartsView(View):
    @login_required
    def get(self, request):
        user = request.user

        cart_list = [{
            'id'           : item.id,
            'product_name' : item.product.name,
            'quantity'     : item.quantity,
            'size'         : item.option.size,
            'product_price': item.option.price,
            'image_url'    : item.product.thumbnail_image_url,
            'price'        : int(item.option.price) * int(item.quantity)
        } for item in Cart.objects.filter(user=user)]

        total_price = Cart.objects.filter(user=2).aggregate(
        		total=Sum(F('option__price')*F('quantity'))['total'] or 0

        shipping_price = 0 if total_price > FREE_SHIPPING or not total_price else 2500   

        return JsonResponse({
            "Cart"       : cart_list,
            "shipping"   : shipping_price,
            "total_price": total_price
            }, status=200)
            

우선 일정 금액 이상이면 배송비를 무료로 하는데,

일정 금액(FREE_SHIPPING)을 상수화 하여 값을 지정하였다.

그리고 total_priceaggregate를 사용하여,

해당하는 Cart객체의 상품 가격과 수량을 곱한 다음 전부 더해주었다.

{ 'total' : total_price } # 해당 장바구니의 총 가격 

하지만 이렇게 되면 장바구니가 비어있는 유저에는 가격과 수량이 존재하지 않아,

변수에 None값이 출력되기에 or 0을 추가하여 0으로 지정되게 하였다.

Coalesce 사용

이럴 경우에 사용하는 django 메소드가 있는데, 그것이 바로 Coalesce이다.

Coalesce?

django 공식문서에서는 아래와 같이 설명하고 있다.

Coalesce는 둘 이상의 필드 이름 또는 표현식 목록을 승인하고 널이 아닌 첫 번째 값을 리턴합니다. (빈 문자열은 널값으로 간주되지 않음)

즉, 차례로 값을 확인하여 null값이 아닌 값을 지정한다는 뜻이다.

문제 발생

그래서 이 방법을 사용하여 아래와 같이 실행하였다.

>>> from django.db.functions import Coalesce
>>> from django.db.models    import Sum,F
>>> from carts.models        import Cart
>>>
>>> total_price = Cart.objects.filter(user_id=2).aggregate(
		total=Coalesce(Sum(F('option__price')*F('quantity')),0))['total']
      

하지만 이렇게 실행하였을때, 값이 지정되지 않고 에러가 발생하였다.

그 이유를 찾아보니 위에서 보던 공식문서에 자세한 부분을 살펴보면,

 ...Each argument must be of a similar type,
 so mixing text and numbers will result in a database error.

각각의 타입형이 다르면 연산이 되지 않기 때문에 주의해야 한다고 쓰여있다.
(이래서 자세히 읽어봐야 한다.)

option__price 가 Decimal type으로 지정되어 있고,
quantity0이 Integer type이기 때문에 연산에서 에러가 발생한 것이다.

해결방법

django에서는 결합하려는 필드의 유형이 다른 경우 어떤 종류의 필드가 반환되는지 알려야 한다.

그래서 해결한 방법이 output_field를 설정해주는 것이다.

>>> from django.db.functions import Coalesce
>>> from django.db.models    import Sum,F, IntegerField
>>> from carts.models        import Cart
>>>
>>> total_price = Cart.objects.filter(user_id=2).aggregate(
		total=Coalesce(Sum(F('option__price')*F('quantity')), 0, output_field=IntegerField()))['total']

output_fieldIntegerField를 지정하면,

django에게 필드의 유형을 알려주게 되면서 해결이 가능하다.

참조
(https://docs.djangoproject.com/en/3.2/ref/models/database-functions/)
(https://stackoverflow.com/questions/38546108/django-aggregation-expression-contains-mixed-types-you-must-set-output-field)

0개의 댓글