Djangoでショッピングカートを作りたい5

いよいよショッピングカートを作っていきます。
$ python3 manage.py startapp cart

setting.py

1
2
3
4
5
6
7
8
INSTALLED_APPS = [
    'shop',
    'search',
    'cart',
    // 省略
]
// 省略
        'DIRS': [os.path.join(BASE_DIR, 'shop', 'templates/'), os.path.join(BASE_DIR, 'search', 'templates/'), os.path.join(BASE_DIR, 'cart', 'templates/')],

cart/models.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from django.db import models
from shop.models import Product
 
class Cart(models.Model):
    cart_id = models.CharField(max_length=250, blank=True)
    date_added = models.DateField(auto_now_add=True)
 
    class Meta:
        db_table = 'Cart'
        ordering = ['date_added']
 
    def __str__(self):
        return self.cart_id
 
class CartItem(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    cart = models.ForeignKey(Cart, on_delete=models.CASCADE)
    quantity = models.IntegerField()
    active = models.BooleanField(default=True)
 
    class Meta:
        db_table = 'CartItem'
 
    def sub_total(self):
        return self.product.price * self.quantity
 
    def __str__(self):
        return self.product.name

$ python3 manage.py makemigrations cart
$ python3 manage.py migrate

cart/urls.py

1
2
3
4
5
6
7
8
from django.urls import path
from . import views
 
app_name = 'cart'
 
urlpatterns = [
    path('', views.cart_detail, name='cart_detail'),
]

urls.py

1
2
3
4
5
6
urlpatterns = [
    path('admin/', admin.site.urls),
    path('shop/', include('shop.urls')),
    path('search/', include('search.urls')),
    path('cart/', include('cart.urls')),
]

cart/views.py
L session.session_keyでセッションの値を取得する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from django.shortcuts import render, redirect
from .models import Cart, CartItem
from django.core.exceptions import ObjectDoesNotExist
 
def _cart_id(request):
    cart = request.session.session_key
    if not cart:
        cart = request.session.create()
    return cart
 
def cart_detail(request, total=0, counter=0, cart_items = None):
    try:
        cart = Cart.objects.get(cart_id=_cart_id(request))
        cart_items = CartItem.objects.filter(cart=cart, active=True)
        for cart_item in cart_items:
            total += (cart_item.product.price * cart_item.quantity)
            counter += cart_item.quantity
    except ObjectDoesNotExist:
        pass
 
    return render(request, 'cart/cart.html', dict(cart_items = cart_items, total = total, counter = counter))

cart/template/cart/cart.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
{% extends "base.html" %}
{% load static %}
 
{% block metadescription %}
    This is the shopping cart page.. Proceed to review your items and place the order.
{% endblock %}
 
{% block title %}
    Cart - Various Product Store
{% endblock %}
 
{% block content %}
    {% if not cart_items %}
    <div>
        <div class="text-center">
            <br>
            <h1 class="text center my_title">Your shopping cart is empty</h1>
            <br>
            <p class="text-center">
                Please click <a href="{% url 'shop:all_product' %}">here</a> to continue shopping.
            </p>
        </div>
    </div>
    {% else %}
    <div>
        <div class="text-center">
            <br>
            <h1 class="text-center my_title">
                Your shopping cart
            </h1>
        </div>
        <br>
    </div>
    <div class="row mx-auto">
        <div class="col-12 col-sm-12 col-lg-6 text-center">
            <table class="table my_custom_table">
                <thread class="my_custom_thread">
                    <tr>
                        <th colspan="5">
                            Your items
                        </th>
                    </tr>
                </thread>
                <tbody>
                    {% for cart_item in cart_items %}
                    <tr>
                        <td><a href="cart_item.product.get_absolute_url"><img src="{{cart_item.product.image.url}}" alt="" class="float-left rounded custom_image"></a></td>
                        <td class="text-left">
                            {{cart_item.product.name}}
                            <br>
                            SKU: {{cart_item.product.id}}
                            <br>
                            Unit Price: ${{cart_item.product.price}}
                            <br>
                            Qty: {{cart_item.quantity}} x ${{cart_item.product.price}}
                        </td>
                        <td>
                            ${{cart_item.sub_total}}
                        </td>
                        {% if cart_item.quantity < cart_item.product.stock %}
                        <td>
                            <a href="{% url 'cart:add_cart' cart_item.product.id %}" class="custom_a"><i class="fas fa-plus-circle custom_icon"></i></a>
 
                            <a href="" class="custom_a"><i class="fas fa-minus-circle custom_icon"></a>
 
                            <a href="" class="custom_item"><i class="far fa-trash-alt"></a>
                        </td>
                        {% else %}
                        <td>
                            <a href="" class="custom_a"><i class="fas fa-minus-circle custom_icon"></a>
 
                            <a href="" class="custom_item"><i class="far fa-trash-alt"></i></a>
                        </td>
                        <td></td>
                        {% endif %}
                    </tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
        <div class="col-12 col-sm-12 col-lg-6 text-center">
            <table class="table my_custom_table">
                <thread class="my_custom_thead">
                    <tr>
                        <th>
                            Checkout
                        </th>
                    </tr>
                </thread>
                <tbody>
                    <tr>
                        <td>
                            Please review your shopping cart item before proceeding with the order payment.
                        </td>
                    </tr>
                    <tr>
                        <td class="text-left">
                            Your total is: <strong>${{total}}</strong>
                        </td>
                    </tr>
                </tbody>
            </table>
            <div class="mx-auto">
                <a href="{% url 'shop:all_product' %}" class="btn-secondary btn-block my_custom_button">Continue Shopping</a>
            </div>
        </div>
    </div>
    {% endif %}
{% endblock %}

models.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from shop.models import Product
 
def add_cart(request, Product_id):
    product = Product.objects.get(id=product_id)
    try:
        cart = Cart.objects.get(cart_id=_cart_id(request))
    except Cart.DoesNotExist:
        cart = Cart.objects.create(
                cart_id = _cart_id(request)
            )
        cart.save()
    try:
        cart_item = CartItem.objects.get(product=product, cart=cart)
        cart_item.quantity += 1
        cart_item.save()
    except CartItem.DoesNotExist:
        cart_item = CartItem.objects.create(
                product = product,
                quantity = 1,
                cart = cart
            )
        cart_item.save()
    return redirect('cart:cart_detail')

urls.py

1
2
3
4
urlpatterns = [
    path('add/<int:product_id>/', views.add_cart, name='add_cart'),
    path('', views.cart_detail, name='cart_detail'),
]

product_detail.html

1
<a class="btn btn-secondary" href="{% url 'cart:add_cart' product.id %}">Add to Cart</a>

cart/views.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def cart_remove(request, product_id):
    cart = Cart.objects.get(cart_id=_cart_id(request))
    product = get_object_or_404(Product, id=product_id)
    cart_item = CartItem.objects.get(product=product, cart=cart)
    if cart_item.quantity > 1:
        cart_item.quantity -= 1
        cart_item.save()
    else:
        cart_item.delete()
    return redirect('cart:cart_detail')
 
def full_remove(request, product_id):
    cart = Cart.objects.get(cart_id=_cart_id(request))
    product = get_object_or_404(Product, id=product_id)
    cart_item = CartItem.objects.get(product=product, cart=cart)
    cart_item.delete()
    return redirect('cart:cart_detail')

urls.py

1
2
3
4
5
6
7
8
app_name = 'cart'
 
urlpatterns = [
    path('add/<int:product_id>/', views.add_cart, name='add_cart'),
    path('', views.cart_detail, name='cart_detail'),
    path('remove/<int:product_id>/', views.cart_remove, name='cart_remove'),
    path('full_remove/<int:product_id>/', views.full_remove, name='full_remove')
]

cart/context_processors.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from .models import Cart, CartItem
from .views import _cart_id
 
def counter(request):
    item_count = 0
    if 'admin' in request.path:
        return {}
    else:
        try:
            cart = Cart.objects.filter(cart_id=_cart_id(request))
            cart_items = CartItem.objects.all().filter(cart=cart[:1])
            for cart_item in cart_items:
                item_count += cart_item.quantity
        except Cart.DoesNotExist:
            item_count = 0
    return dict(item_count = item_count)

settings.py

1
2
3
4
5
6
7
'context_processors': [
    'django.template.context_processors.debug',
    'django.template.context_processors.request',
    'django.contrib.auth.context_processors.auth',
    'django.contrib.messages.context_processors.messages',
    'cart.context_processors.counter',
],

navbar.html

1
2
3
4
5
{% if item_count > 0 %}
<li class="nav-item">
    <a class="nav-link" href="{% url 'cart:cart_detail' %}">({{item_count}})</a>
</li>
{% endif %}

cart.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{% if cart_item.quantity < cart_item.product.stock %}
<td>
    <a href="{% url 'cart:add_cart' cart_item.product.id %}" class="custom_a"><i class="fas fa-plus-circle custom_icon"></i></a>
 
    <a href="{% url 'cart:cart_remove' cart_item.product.id %}" class="custom_a"><i class="fas fa-minus-circle custom_icon"></a>
 
    <a href="{% url 'cart:full_remove' cart_item.product.id %}" class="custom_item"><i class="far fa-trash-alt"></a>
</td>
{% else %}
<td>
    <a href="{% url 'cart:cart_remove' cart_item.product.id %}" class="custom_a"><i class="fas fa-minus-circle custom_icon"></a>
 
    <a href="{% url 'cart:full_remove' cart_item.product.id %}" class="custom_item"><i class="far fa-trash-alt"></i></a>
</td>
<td></td>
{% endif %}

なるほど、ただこれだと、ログアウトした時の処理などが入ってないから、完成には遠いな。Libraryはないのかしら?