[Django] Cart functionality Add
Cart (3)
/ 장바구니 만들기 /
AJAX integration - Add
- Product-info 에서 장바구니 버튼을 눌렀을 때 value에 상품 id 값을 넣어줌
product-info.html
<button type="button" id="add-button" value="{{product.id}}" class="btn btn-secondary btn-sm">
Add to cart
</button>
...
$(document).on('click', '#add-button', function (e) {
e.preventDefault();
$.ajax({
type: 'POST',
url: '{% url "cart-add" %}',
data: {
product_id: $('#add-button').val(),
product_quantity: $('#result').text(),
csrfmiddlewaretoken: "{{csrf_token}}",
action: 'post'
},
success: function (json) {
console.log(json)
},
error: function (xhr, errmsg, err) {}
});
})
- urls.py 에
path('add/', views.cart_add, name='cart-add'),
를 추가해주고 name 값 ‘cart-add’ 를 ajax url에 연결해준다.- product_id 는 위에서 지정해준
product.id
값을 갖고 온다.- product_quantity 는 이전에 수량 변화에 대한 id 값 result를 넣고 text 값으로 갖고 오면 된다.
- 장고에서는 어차피 CSRF 토큰을 기본적으로 사용하니 미리 발급해준다.
- 참고 : https://chagokx2.tistory.com/49
cart>views.py
from django.shortcuts import render
from .cart import Cart
from store.models import Product
from django.shortcuts import get_object_or_404
from django.http import JsonResponse
def cart_add(request):
cart = Cart(request)
if request.POST.get('action') == 'post': # match lower case in action from product-info.html
product_id = int(request.POST.get('product_id'))
product_quantity = int(request.POST.get('product_quantity'))
product = get_object_or_404(Product, id=product_id)
cart.add(product=product, product_qty=product_quantity)
# session updating in realtime when you click the button
cart_quantity = cart.__len__()
response = JsonResponse({'product titke': product.title, 'quantity':product_quantity})
return response
- cart.py 에 있는 Cart 클래스를 불러준다.
get_object_or_404
로 유효성 검사를 해준다. 해당 product_id 값이 Product에 있으면 cart의 add 함수를 불러와서 코드가 실행된다.
- cart에서 add 함수를 불러와야 하므로 cart.py에 add 함수를 만들어준다.
cart.py
class Cart():
...
def add(self, product, product_qty):
product_id = str(product.id)
if product_id in self.cart:
self.cart[product_id]['qty'] = product_qty
else:
self.cart[product_id] = {'price': str(product.price), 'qty': product_qty}
self.session.modified = True # session update
- 아이템을 장바구니에 추가 했을 때 이미 장바구니에 해당 아이템이 있다면 가격정부는 이미 있으므로 굳이 가격 정보를 또 넣어줄 필요가 없다
- 이 때는 수량만 반영해주면 된다.
- 반면 해당 아이템이 장바구니에 없다면 아무런 정보가 없으니 가격과 수량 모두 반영해주면 된다.
- 수량과 이름 모두 잘 반영되는걸 콘솔에서 확인하면 끝
장바구니에 숫자 표시해주기
- 현재 장바구니에는 딱히 표시되는게 없는데 장바구니에 아이템이 추가되면 아이템 갯수만큼 반영되도록 해보자.
base.html
<a type="button" role="button" href="{% url 'cart-summary' %}" class="btn btn-outline-secondary">
<i class="fa fa-shopping-cart" aria-hidden="true"> </i>
<div id="cart-qty" class='d-inline-flex '>
0
</div>
</a>
- 장바구니에 숫자 표시
cart > views.py
def cart_add(request):
cart = Cart(request)
if request.POST.get('action') == 'post': # match lower case in action from product-info.html
product_id = int(request.POST.get('product_id'))
product_quantity = int(request.POST.get('product_quantity'))
product = get_object_or_404(Product, id=product_id)
cart.add(product=product, product_qty=product_quantity)
# response = JsonResponse({'product titke': product.title, 'quantity':product_quantity})
response = JsonResponse({'qty': product_quantity})
return response
- 장바구니에서 상품 이름은 필요 없으므로 qty 라는 키 값으로 상품 수량을 장바구니에 반영해준다.
cart > product-info.html
success: function (json) {
//console.log(json)
document.getElementById("cart-qty")
.textContent = json.qty
// need to be matched with JsonResponse dictionary key in cart_add function from view.py
},
document.getElementById("cart-qty").textContent = json.qty
는 base.html 에서 id 값cart-qty
의 텍스트 값이 views.py 의 키 값 ‘qty’ 의 벨류 값으로 반영됨 -
-
- 하지만 새로고침을 하면 데이터가 날아간다.
- 따라서 세션에 저장된 데이터(수량) 가 계속 페이지에 반영되도록 작업을 해줘야한다.
cart.py
def __len__(self):
try:
return sum(item['qty'] for item in self.cart.values())
except:
return 0
- self.cart 딕셔너리에 담겨 있는 키 값은 product의 id 값이다.
- 예를들어 티쳐츠는 id 1번 팬츠는 2번 이런식
- 따라서 values 값으로 호출을 해야한다. ->
[{'price':'45000', 'qty':2}, {'price':'60000', 'qty':3}]
- 해당 값의 키값 qty로 호출
- 값이 없으면 0으로 리턴
base.html
<div id="cart-qty" class='d-inline-flex '>
{% with qty_amount=cart|length %}
{% if qty_amount > 0 %}
{{ qty_amount }}
{% else %}
0
{% endif %}
{% endwith %}
</div>
- 전역으로 사용할 수 있겠금 TEMPLATES에 cart 를 등록해줬으므로 with 템플릿 태그를 사용해서 length를 호출해준다.
- qty_amount 가 0보다 크면 qty_amount를 출력해주고 아니면 0을 출력
- Wtih statement 참고 : https://jinja.palletsprojects.com/en/3.1.x/templates/
Issue
- 이전에 티셔츠 상품을 방구니에 넣고 새로운 상품을 넣으면 현재 상품 갯수만 반영되고 합산이 안된다.
- 여기서 새로고침을 눌러줘야지만 제대로 반영이 된다.
- 해당 부분을 해결해주기 위해서는 세션에서 전체수량을 넘겨줘야한다.
cart>views.py
def cart_add(request):
cart = Cart(request)
if request.POST.get('action') == 'post': # match lower case in action from product-info.html
product_id = int(request.POST.get('product_id'))
product_quantity = int(request.POST.get('product_quantity'))
product = get_object_or_404(Product, id=product_id)
cart.add(product=product, product_qty=product_quantity)
# session updating in realtime when you click the button
cart_quantity = cart.__len__()
# response = JsonResponse({'qty': product_quantity})
response = JsonResponse({'qty': cart_quantity})
return response
cart.__len__()
으로 세션에 있는 데이터를 불러와서 cart_quantity 객체를 만들고 qty의 키값의 벨류로 넣어주면 실시간으로 업데이트가 잘 된다.
cart.py
def add(self, product, product_qty):
product_id = str(product.id)
if product_id in self.cart:
self.cart[product_id]['qty'] += product_qty
else:
self.cart[product_id] = {'price': str(product.price), 'qty': product_qty}
self.session.modified = True # session update
- 또한 이전에
self.cart[product_id]['qty'] = product_qty
부분을 += 로 중첩으로 바꿔줘야지 안 그러면 셔츠 2개 장바구니 넣고 팬츠 3개 넣었다가 다시 셔츠 1개를 장바구니에 넣으면 셔츠가 총 3개로 쌓이는게 아니라 다시 1개로 줄어든다.
- 논리를 잘 생각하면서 짜면 된다.
댓글남기기