[Django] Shopping Mall (12)
체크아웃 페이지 만들기
carts>views.py
@login_required(login_url='login')
def checkout(request, total=0, quantity=0, cart_items=None):
try:
tax=0
grand_total=0
cart = Cart.objects.get(cart_id=_cart_id(request))
cart_items = CartItem.objects.filter(cart=cart, is_active=True)
for cart_item in cart_items:
total +=(cart_item.product.price * cart_item.quantity)
quantity += (cart_item.quantity)
tax = int(total * 0.1) # 부가가치세
grand_total = tax + total
except ObjectDoesNotExist:
pass
context = {
'total': total,
'quantity': quantity,
'cart_items': cart_items,
'tax' : tax,
'grand_total': grand_total,
}
return render(request, 'store/checkout.html', context)
- 기존에 만들었던
cart
를 재활용해서 장바구니에 있던 상품 정보들을 가져왔다. 그리고 장바구니에서 결제를 눌렀을 때 로그인이 되어 있으면 체크아웃 페이지로 아닌 경우에는 자동으로 로그인 페이지로 가도록 데코레이터@login_required
를 사용했다.- 현재 로그인하면 장바구니에 있던 세션정보가 넘어오지 않기 때문에 이를 연결해주기 위해서 모델을 수정해줘야 한다.
- 로그인하면 세션아이디가 바뀜
carts>models.py
class CartItem(models.Model):
user = models.ForeignKey(Account, on_delete=models.CASCADE, null=True)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
variations = models.ManyToManyField(Variation, blank=True)
cart = models.ForeignKey(Cart, on_delete=models.CASCADE, null=True)
quantity = models.IntegerField()
is_active = models.BooleanField(default=True)
def sub_total(self):
return self.product.price * self.quantity
def __unicode__(self):
return self.product
로그인을 안 한 상태에서 로그인을 하면 세션이 초기화 된다. (장바구니도 날라간다는 소리) 로그인을 한 상태에서는 장바구니에 아이템을 담으면 로그아웃을 해도 계속 트래킹 할 수 있도록
Account
테이블을 참조해준다.
accounts>views.py
def login(request):
if request.method == 'POST':
email = request.POST['email']
password = request.POST['password']
user = auth.authenticate(email=email, password=password)
if user is not None:
try:
cart = Cart.objects.get(cart_id=_cart_id(request))
is_cart_item_exists = CartItem.objects
.filter(cart=cart).exists()
if is_cart_item_exists:
cart_item = CartItem.objects.filter(cart=cart)
for item in cart_item:
item.user = user
item.save()
except:
pass
auth.login(request, user)
messages.success(request, "You are new logged in.")
return redirect('dashboard')
else:
messages.error(request, 'Invalid login credentials')
return redirect('login')
return render(request, 'accounts/login.html')
cart
를 먼저 선언하며서cart_id
의 정보를 갖고 온다. 자식 테이블인CartItem
은 부모테이블cart
를 참조하고 있다 예를 들어 장바구니 1번은 셔츠 m사이즈 바지 L 사이즈 3개 이런식으로 정보들이 담겨있고 결론은 장바구니에 아이템이 담겨있었던건지 아닌지를 검사해서 그 결과를is_cart_item_exists
에 담는다.cart_id
는 세션 값이다.is_cart_item_exists
가 참이면 아이템의 모든 정보를product_variation
에 담아준다. 그 후 장바구니에 여러 개의 물건이 있을 수 있으므로 반복문으로 다시 리스트에 담아준다.
carts>context_processors.py
def counter(request):
cart_count = 0
if 'admin' in request.path:
return {}
else:
try:
cart = Cart.objects.filter(cart_id=_cart_id(request))
if request.user.is_authenticated:
cart_items = CartItem.objects.all()
.filter(user=request.user)
else:
cart_items = CartItem.objects.all()
.filter(cart=cart[:1])
for cart_item in cart_items:
cart_count += cart_item.quantity
except Cart.DoesNotExist:
cart_count = 0
return dict(cart_count=cart_count)
- 이전과 달리
CartItem
테이블은Account
테이블을 참조 하므로 로그인을 하면 user 값을 갖고 오고 로그인이 되어있지 않은 상태는 기존의 방식대로 장바구니를 카운팅 한다.
carts>views.py
def cart(request, total=0, quantity=0, cart_items=None):
try:
tax=0
grand_total=0
# 추가
if request.user.is_authenticated:
cart_items = CartItem.objects
.filter(user=request.user, is_active=True)
#
else:
cart = Cart.objects.get(cart_id=_cart_id(request))
cart_items = CartItem.objects
.filter(cart=cart, is_active=True)
for cart_item in cart_items:
total +=(cart_item.product.price * cart_item.quantity)
quantity += (cart_item.quantity)
tax = int(total * 0.1) # 부가가치세
grand_total = tax + total
except ObjectDoesNotExist:
pass
context = {
'total': total,
'quantity': quantity,
'cart_items': cart_items,
'tax' : tax,
'grand_total': grand_total,
}
return render(request, 'store/cart.html', context)
- 위의 로직과 똑같이 로그인을 했을 때와 로그인 하지 않았을 때로 나눠서 로직을 짜준다.
문제점
원래 장바구니에 아이템이 있는 상태에서 로그아웃한 상태로 장바구니에 아이템을 넣고 다시 로그인 했을 때 중복된 아이템이 분리되어서 나왔다. 로그인 부분에서 인식을 제대로 못 해서 발생되는 부분이었다.
accounts>views.py
def login(request):
if request.method == 'POST':
email = request.POST['email']
password = request.POST['password']
user = auth.authenticate(email=email, password=password)
if user is not None:
try:
cart = Cart.objects.get(cart_id=_cart_id(request))
is_cart_item_exists = CartItem.objects
.filter(cart=cart).exists()
if is_cart_item_exists:
cart_item = CartItem.objects.filter(cart=cart)
# Getting the product variations by cart id
product_variation = []
for item in cart_item:
variation = item.variations.all()
product_variation.append(list(variation))
# Get the cart items from the user to access his product variations
cart_item = CartItem.objects.filter(user=user)
ex_var_list = []
id = []
for item in cart_item:
existing_variation = item.variations.all()
ex_var_list.append(list(existing_variation))
id.append(item.id)
for pr in product_variation:
if pr in ex_var_list:
index = ex_var_list.index(pr)
item_id = id[index]
item = CartItem.objects.get(id=item_id)
item.quantity += 1
item.user = user
item.save()
else:
cart_item = CartItem.objects
.filter(cart=cart)
for item in cart_item:
item.user = user
item.save()
except:
pass
auth.login(request, user)
messages.success(request, "You are new logged in.")
return redirect('dashboard')
else:
messages.error(request, 'Invalid login credentials')
return redirect('login')
return render(request, 'accounts/login.html')
- 이전에 장바구니와 문제 해결이 비슷하다. 우선 장바구니에 물건이 있다면 해당 정보를
product_variation
라는 빈 리스트를 만들어서 넣어주고- 그다음 필터로 user (로그인 했을 때) 정보에 담겨 있던 장바구니 정보를 불러와서
ex_var_list
에 넣어주고 추가로 아이템 분류를 위해id
의 빈 리스트를 만들어서 각 id 값도 따로 저장해 준다.- 반복문으로 이전에 로그인 했을 때의 아이템이 존재한다면 +1 로 업데이트해 주면 완성
문제점 2
- 기능 검사중 이전에는 잘 되던 remove 또는 - 버튼을 누르면 오류가 났다
def remove_cart(request, product_id, cart_item_id):
product = get_object_or_404(Product, id=product_id)
try:
if request.user.is_autehnticated:
cart_item = CartItem.objects
.get(product=product,
user=request.user, id=cart_item_id)
else:
cart = Cart.objects.get(cart_id=_cart_id(request))
cart_item = CartItem.objects
.get(product=product, cart=cart, id=cart_item_id)
if cart_item.quantity >1:
cart_item.quantity -=1
cart_item.save()
else:
cart_item.delete()
except:
pass
return redirect('cart')
- 유저가 로그인 했을 때와 안 했을 때를 구분해 줘서 짜준다.
- 로그인 했을 때는 user에 이미
cart
정보가 있어서 상관없지만 로그아웃되어있는 상태에서는 아무런 정보가 없기 때문에 else 문에서cart
를 선언해 줘야 한다.- remove 도 같은 논리로 짜주면 된다.
댓글남기기