Online Shop_3

박다현·2023년 7월 27일
0

likelion

목록 보기
15/23
post-thumbnail

01 장바구니


cart

선택한 상품을 주문하기 위해 보관하는 기능
model 생성 > DB 저장 방법 X

장바구니에서는 session 기능을 활용


Session

모델을 생성한 후, 세션(Session) 기능을 활용하여 모델을 메모리에 유지하는 방식

세션은 클라이언트와 서버 간에 연결을 유지하며, 클라이언트의 요청에 따라 해당 세션에서 모델을 실행하고 결과를 반환


장점

  • 세션을 통해 모델을 메모리에 유지함으로써, 반복적인 모델 로딩 시간 단축

  • 요청이 들어올 때마다 매번 모델을 불러오는 대신, 세션을 통해 상태를 유지하므로 처리 속도가 향상 가능

  • 효율적인 호출 in 모델을 여러 번 호출해야 하는 상황

단점

  • 세션은 일시적으로 메모리를 점유하므로, 동시에 많은 세션을 유지하는 경우 서버의 메모리 부담이 발생 가능성 존재

  • 서버의 장애나 다운 시 세션 상태가 손실될 수 있으므로, 이에 대비하는 적절한 대응 필요

  • 모델의 크기가 매우 크거나, 여러 모델을 동시에 다루어야 하는 경우 메모리 사용량이 증가하여 서버 성능에 영향 미칠 가능성 존재



STEP 1 cart app

python manage.py startapp cart

STEP 2 config/settings.py

INSTALLED_APPS = [
	'cart',
]

STEP 3 cart/cart.py 생성

from decimal import Decimal

import requests
from django.conf import settings
from shop.models import Product

class Cart(object):
    def __init__(self, request): // 생성자 역할, 클래스 객체를 선언하면 자동으로 실행해 객체를 생성
        self.session = request.session
        cart = self.session.get(settings.CART_ID) # settings에 CART_ID와 연결
        if not cart : # cart 정보 없을 경우
            cart = self.session[settings.CART_ID] = {} # 새 딕셔너리 생성
        self.cart = cart

    def __len__(self): # 장바구니에 있는 상품의 수량을 전부 더한 결과
    // 장바구니에 들어있는 제품의 quantity 항목들을 전부 더한 결과 제공
        return sum(item['quantity'] for item in self.cart.values())

    def __iter__(self): # for문 사용시 어떤 요소를 건내줄지 지정
    // for문 안에 객체를 넣을 수 있도록 함
        product_ids = self.cart.keys() // 제품 번호 목록을 가져옴

        products = Product.objects.filter(id__in=product_ids) # 장바구니에 있는 제품 정보만 Product db에서 가져옴

        for product in products: // 제품 정보를 하나씩 읽어옴
            self.cart[str(product.id)]['product'] = product # session에 키 값들을 넣을 때 문자로 넣음

        for item in self.cart.values(): // 장바구니에 있는 제품을 한 개씩 불러옴
            item['total_price'] = item['price'] * item['quantity'] // 가격 x item 수를 총 가격에 넣고
            item['price'] = Decimal(item['price']) // 가격에 숫자형으로 바꿔 item에 넣는다

            yield item

    # 장바구니에 넣기
    def add(self, product, quantity=1, is_update=False): # 제품 정보를 업데이트하는지 아닌지 확인
        product_id = str(product.id)
        if product_id not in self.cart:
            self.cart[product_id] = {'quantity':0, 'price':str(product.price)}

        if is_update:
            self.cart[product_id]['quantity'] = quantity
        else:
            self.cart[product_id]['quantity'] += quantity
        self.save()

    # 장바구니 저장하기
    def save(self):
        self.session[settings.CART_ID] = self.cart
        self.session.modified = True

    # 장바구니에서 삭제하기
    def remove(self, product):
        product_id = str(product.id)
        if product_id in self.cart:  
            del(self.cart[product_id]) 
            self.save() 
            
    # 장바구니 비우기
    def clear(self):
        self.session[settings.CART_ID] = {}
        self.session.modified = True
        
 // session으로 사용하는 방식이기 떄문에 request.session에 데이터를 저장하고 꺼내오는 구조

    # 장바구니에 있는 제품의 총 가격 계산
    def get_product_total(self):
        return sum(Decimal(item['price']) * item['quantity'] for item in self.cart.values())
        
// save 와 clear 메서드에서도 settings.CART_ID 사용
> session 에 값을 저장해 키 값을 설정하고 이 값을 가져다 사용

STEP 4 config/settings.py

CART_ID = 'cart_in_session'

// session 에 값을 저장하려면 키 값을 설정해야 하는데 settings.py 에 CART_ID라는 변수 만들고 거기에 설정된 값을 가져다 사용하기 위해 settings.CART_ID 라는 변수 사용

02 form / View / Url


STEP 1 form 작성

from django import forms

class AddProductForm(forms.Form): // 장바구니에 상품 추가를 위한 폼
	quantity = forms.IntegerField()
    is_update = forms.BooleanField(required=False, initial=False, widget=forms.HiddenInput
    
 - is_update=False : 상품 수량을 선택하고 추가할 때마다 현재 장바구니 수량에 더해지는 방식
 - is_update=True : 값이 바로 업데이트 되는 방식

STEP 2 View 작성

from django.shortcuts import render,redirect, get_object_or_404
from django.views.decorators.http import require_POST

from shop.models import Product
from .forms import AddProductForm
from .cart import Cart

# Create your views here.

# 장바구니 추가 뷰
@require_POST
def add(request, product_id):
    cart = Cart(request)
    product = get_object_or_404(Product, id=product_id)

    form = AddProductForm(request.POST)
    if form.is_valid():
        cd = form.cleaned_data
        cart.add(product=product, quantity=cd['quantity'],is_update=['is_update'])

    return redirect('cart:detail')

# 장바구니 삭제 뷰
def remove(request,product_id):
    cart = Cart(request)
    product = get_object_or_404(Product, id=product_id)
    cart.remove(product)
    return redirect('cart:detail')

# 장바구니 정보 뷰
def detail(request):
    cart = Cart(request)
    for product in cart:
        product['quantity_form'] = AddProductForm(initial={'quantity':product['quantity'], 'is_update':True})

    return render(request, 'cart/detail.html',{'cart':cart})

STEP 3 Url 작성

# cart/urls.py

from django.urls import path
from .views import*

app_name = 'cart'

urlpatterns = [
    path('',detail, name='detail'),
    path('add/<int:product_id>', add, name='product_add'),
    path('remove/<product_id>', remove, name='product_remove'),
]
# config/urls.py

path('cart/',include('cart.urls')),


03 Template


STEP 1 cart/templates/cart/detail.html

{% extends "base.html" %}
{% load static %}

{% block title %}
    Shopping cart
{% endblock %}

{% block content %}
    <table class="table table-striped">
        <thead>
            <tr>
                <th scope="col">Image</th>
                <th scope="col">Product</th>
                <th scope="col">Quantity</th>
                <th scope="col">Remove</th>
                <th scope="col">Unit price</th>
                <th scope="col">Price</th>
            </tr>
        </thead>
        <tbody>
        {% for item in cart %}
            {% with product=item.product %}
            <tr>
                <th scope="row">
                    <a href="{{ product.get_absolute_url }}">
                        <img src="{{ product.image.url }}" class="img-thumbnail">
                    </a>
                </th>
                <td>{{ product.name }}</td>
                <td>
                    <form action="{% url 'cart:product_add' product.id %}" method="post">
                        {{ item.quantity_form.quantity }}
                        {{ item.quantity_form.is_update }}
                        <input type="submit" class="btn btn-primary" value="Update">
                        {% csrf_token %}
                    </form>
                </td>
                <td><a href="{% url 'cart:product_remove' product.id %}">Remove</a></td>
                <td class="num">${{ item.price }}</td>
                <td class="num">${{ item.total_price }}</td>
            </tr>
            {% endwith %}
        {% endfor %}
        {% if cart.coupon %}
            <tr class="subtotal">
                <td>Subtotal</td>
                <td colspan="4"></td>
                <td >${{ cart.get_product_total }}</td>
            </tr>
            <tr>
                <td>"{{ cart.coupon.code }}" coupon (${{ cart.coupon.amount }})</td>
                <td colspan="4"></td>
                <td >- ${{ cart.get_discount_total|floatformat:"2" }}</td>
            </tr>
        {% endif %}
        <tr class="total">
            <td>Total</td>
            <td colspan="4"></td>
            <td class="num">${{ cart.get_total_price|floatformat:"2" }}</td>
        </tr>
        </tbody>
    </table>

    <p class="text-right">
        <a href="{% url 'shop:product_all' %}" class="btn btn-secondary">Continue shopping</a>
        <a href="#" class="btn btn-secondary">Checkout</a>
    </p>
{% endblock %}

STEP 2 View 수정

from cart.forms import AddProductForm

# 상품 상세 페이지 뷰
def product_detail(request, id, product_slug=None):
    product = get_object_or_404(Product, id=id, slug=product_slug)
    add_to_cart = AddProductForm(initial={'quantity':1})
    return render(request,'shop/detail.html',{'product':product, 'add_to_cart':add_to_cart})


Online Shop_2 실습에 이어서 장바구니 앱을 만들고 앱에 관한 코드 작성하며 스터디 진행


0개의 댓글