Django開発~ショッピングカート構築編6~検索機能の導入の続きです。
本日は、Shopping Cart を実装します。
<目次>
学習履歴
cartアプリケーション
Shopping Cartとは、購入予定の商品をまとめて管理する機能の事を指します。
Amazonのカートを思い浮かべてください。それです。

まずは、cartアプリケーションをDjangoプロジェクトに追加します。
1 |
make app app=cart |
次に、settings.pyを開いて、cartをDjangoプロジェクトに組み込みます。
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 |
app/app/settings.py INSTALLED_APPS = [ # myapp 'shop', 'search', 'cart', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ] TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'shop', 'templates/'), os.path.join(BASE_DIR, 'search', 'templates/'), os.path.join(BASE_DIR, 'cart', 'templates/')], # 追加 'APP_DIRS': True, 'OPTIONS': { '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アプリケーションの仕様
Cart アプリケーションを追加できたら、このアプリケーションの仕様を考えます。
・カートとカートに追加するアイテムが存在する
・カートは、一覧表示、追加、削除、一括削除ができる
ざっくりとした仕様ですが、ひとまず、この仕様を元にTodoリスト作成します。
②CartItemモデルの作成
③一覧表示できるようにする
④商品追加ができるようにする
⑤商品削除、一括削除ができるようにする

Todoリストは、アプリケーション開発のためのレシピです。このレシピを元にアプリケーションを開発していきましょう
モデルの作成
まずは、Cartモデルを作成します。
このモデルは、カートそのものを表します。
TDDで開発しているため、まずは、テストコードを作成しましょう。
1 2 3 |
rm app/cart/tests.py mkdir app/cart/tests touch app/cart/tests/test_models.py |
続いて、カートモデルが設定通りに作成されるかテストします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
app/cart/tests/test_models.py from django.test import TestCase from django.utils import timezone from cart.models import Cart class ModelTest(TestCase): def test_create_cart(self): Cart.objects.create( cart_id='USERONLY', date_added=timezone.now) c = Cart.objects.all()[0] assert str(c) == c.cart_id |
cart_idは、ユーザーのセッション情報を格納するつもりです。そうすることで、ユーザー(セッション)単位でカートが作成されます。
テストコードを実行しましょう。
1 2 3 4 5 6 7 8 9 10 11 |
make test app=cart __________________ ERROR collecting cart/tests/test_models.py __________________ ImportError while importing test module '/app/cart/tests/test_models.py'. Hint: make sure your test modules/packages have valid Python names. Traceback: cart/tests/test_models.py:4: in <module> from cart.models import Cart E ImportError: cannot import name 'Cart' from 'cart.models' (/app/cart/models.py) !!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!! =============================== 1 error in 0.32s =============================== |
「ImportError: cannot import name ‘Cart’ from ‘cart.models’ (/app/cart/models.py)」とエラーメッセージが出ました。
Cartモデルを作成していないので、当然ですね。
Cartモデルを追加しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
app/cart/models.py from django.db import models 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 |
マイグレーションしましょう。
1 |
make migrate |
テストを実行します。
1 2 3 |
make test app=cart ============================== 1 passed in 1.34s =============================== |
テストがPassしました。同様にCartItemモデルも作成しましょう。
このモデルは、Cartに格納した商品を表します。
例によってテストコード作成からです。
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 |
app/cart/tests/test_models.py from django.test import TestCase from django.utils import timezone from shop.models import Category, Product from cart.models import Cart, CartItem class ModelTest(TestCase): def test_create_cart(self): Cart.objects.create( cart_id='USERONLY', date_added=timezone.now) c = Cart.objects.all()[0] assert str(c) == c.cart_id def test_create_cartitem(self): category = Category.objects.create( name='Black Urban Cushion', slug='black-urban-cushion', description='This is a category for black urban cushion') product = Product.objects.create( name='pag dog', slug='pag-dog', description='Pag dog is as big as cats', category=category, price=30.2, stock=30, available=True) cart = Cart.objects.create( cart_id='USERONLY', date_added=timezone.now) CartItem.objects.create( product = product, cart=cart, quantity=3, active=True) cart_item = CartItem.objects.all()[0] assert str(cart_item) == cart_item.product.name |
Cartに商品を追加するとき、CartItemとして扱います。その為、このCartItemは、CartとProductに結び付きます。
テストを実行してみましょう。
1 2 3 4 5 6 7 8 9 10 11 |
make test app=cart __________________ ERROR collecting cart/tests/test_models.py __________________ ImportError while importing test module '/app/cart/tests/test_models.py'. Hint: make sure your test modules/packages have valid Python names. Traceback: cart/tests/test_models.py:5: in <module> from cart.models import Cart, CartItem E ImportError: cannot import name 'CartItem' from 'cart.models' (/app/cart/models.py) !!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!! =============================== 1 error in 0.30s =============================== |
「E ImportError: cannot import name ‘CartItem’ from ‘cart.models’ (/app/cart/models.py)」になりましたね。
CartItmeをモデルに追加しましょう。
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 |
app/cart/models.py 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 |
マイグレーションを実行します。
1 |
make migrate |
テストを実行します。
1 2 3 |
make test app=cart ============================================ 2 passed in 1.22s ============================================ |
OKですね。
Todoリストから ①と②を削除しましょう。
③一覧表示できるようにする
④商品追加ができるようにする
⑤商品削除、一括削除ができるようにする
一覧表示機能の実装
次は、一覧表示機能を実装しましょう。
まずは、テストコードを書きます。
1 |
touch app/cart/tests/test_views.py |
最初は、カート詳細ページへのリクエストをテストします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
app/cart/tests/test_views.py from django.test import TestCase from django.urls import reverse CART_DETAIL_URL = reverse('cart:cart_detail') class ViewTest(TestCase): def test_correct_urls(self): response = self.client.get(CART_DETAIL_URL) assert response.status_code == 200 |
テストを実行します。
1 2 3 |
make test app=cart E django.urls.exceptions.NoReverseMatch: 'cart' is not a registered namespace |
cart のnamespaceがないと表示されましたね。
このnamespaceは、cartアプリのurls.pyに記述します。
1 |
touch app/cart/urls.py |
1 2 3 4 5 6 7 8 9 10 11 |
app/cart/urls.py from django.urls import path from . import views app_name='cart' urlpatterns = [ path('', views.cart_detail, name='cart_detail'), ] |
テストを実行しましょう。
1 2 3 |
make test app=cart django.urls.exceptions.NoReverseMatch: 'cart' is not a registered namespace |
同じエラーが、まだ表示されますね。
プロジェクトのurls.pyにもパスを記述する必要があるためです。
1 2 3 4 5 6 7 8 9 |
app/app/urls.py urlpatterns = [ path('admin/', admin.site.urls), path('search/', include('search.urls')), path('cart/', include('cart.urls')), # new path('', include('shop.urls')), ] |
テストを実行します。
1 2 3 |
make test app=cart E AttributeError: module 'cart.views' has no attribute 'cart_detail' |
エラーが変わりました。views.pyにcart_detail関数を追加しましょう。
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 |
app/cart/views.py 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_id関数は、Cartオブジェクトの中にセッション情報の有無を確認し、セッション情報が無い場合は、新しくセッションを生成します。
こうすることで、セッションごとにCartオブジェクトを作れる、つまりは他のユーザーから自分のカートの中身を分離できるようにしました。
テストを実行します。
1 2 3 |
make test app=cart django.template.exceptions.TemplateDoesNotExist: cart.html |
cart.htmlがないとのことなので、作成してみましょう。
1 2 |
mkdir -p app/cart/templates/cart touch app/cart/templates/cart/cart.html |
テストを実行しましょう。
1 |
============================================ 3 passed in 1.28s ============================================ |
OKですね。
では、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 110 111 112 113 114 115 116 117 118 119 120 |
app/cart/templates/cart/cart.html {% extends "base.html" %} {% load staticfiles %} {% block metadescription %} This is the shopping cart page.. Proced 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"> <thead class="my_custom_thead"> <tr> <th colspan="5"> Your items </th> </tr> </thead> <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"></i> </a> <a herf="" class="custom_item"> <i class="far fa-trash-alt"></i> </a> </td> {% else %} <td> <a href="" class="custom_a"> <i class="fas fa-minus-circle custom_icon"></i> </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"> <thead class="my_custom_thead"> <tr> <th> Checkout </th> </tr> </thead> <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> <br> {% endif %} {% endblock %} |
「localhost:8000/cart」にアクセスして、画面を確認しましょう。

個別CSSも適用します。
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 |
static/css/custom.css /****Cart Page****/ .my_custom_table { min-width: 400px; font-size: 14px; } .my_custom_thead { font-weight: normal; text-transform: uppercase; letter-spacing: .2em background-color: #f8f9fa!important; } .custom_image { width: 100px; height: 100px; } .custom_a { text-decoration: none; } .custom_icon { text-decoration: none; color: #868e96!important; } .my_custom_button { margin-top: 5px; } |
Todoリストの③が消せますね。
④商品追加ができるようにする
⑤商品削除、一括削除ができるようにする
商品追加機能の実装
方針がブレてしまいますが、ここからはテストコードを書かずに、実装をメインに記述します(すみません)。
views.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 5 6 7 8 9 10 11 12 13 |
app/cart/urls.py from django.urls import path from . import views app_name='cart' urlpatterns = [ # new path('add/<int:product_id>/', views.add_cart, name='add_cart'), path('', views.cart_detail, name='cart_detail'), ] |
product_detail.htmlにこのURLのパスを追加します。
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 |
app/shop/templates/shop/product_detail.html {% extends "base.html" %} {% load staticfiles %} {% block metadescription %} {{ product.description|truncatewords:155 }} {% endblock %} {% block title %} {{ product.name }} - Perfect Cushion Store {% endblock %} {% block content %} <div class="row my_prod_row_class"> <div class="mx-auto"> <p><a href="{% url 'shop:all_product' %}">Home</a>|<a href="{{ product.get_url }}">{{product.name}}</a></p> </div> <div class="container"> <br> <div class="row"> <div class="col-12 col-sm-12 col-md-12 col-lg-6 text-center"> <div style="min-width: 18rem"> <img src="{{product.image.url}}" alt="{{product.name}}"> </div> </div> <div class="col-12 col-sm-12 col-md-12 col-lg-6"> <div> <h1 class="my_prod_title">{{product.name}}</h1> <p>£{{product.price}}</p> <p class="my_title">Product Description</p> <p class="text-justify my_prod_text">{{product.description}}</p> {% if product.stock <= 0 %} <p class="text-justify my_prod_text"><b>Out of Stock</b></p> {% else %} <!-- リンクを追加 --> <a class="btn btn-secondary" href="{% url 'cart:add_cart' product.id %}">Add to Cart</a> {% endif %} </div> </div> </div> </div> </div> |
localhost:8000/にアクセス後、商品の詳細ページに飛び、Add to Cartを押下してみてください。



問題なく表示されましたでしょうか?
これで、Todoリストの④が削除できますね。
⑤商品削除、一括削除ができるようにする
削除機能を実装する。
最後に、cartから商品を削除する機能を実装しましょう。
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 |
app/cart/views.py from django.shortcuts import render, redirect, get_object_or_404 # new from shop.models import Product from .models import Cart, CartItem from django.core.exceptions import ObjectDoesNotExist # new 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 9 10 11 |
from django.urls import path from . import views 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'), ] |
商品を数えるためのpythonファイルを用意します。
1 |
touch app/cart/context_processors.py |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
app/cart/context_processors.py 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) |
これは、Cartの中に入っている商品をカウントする処理です。
settings.pyを開いて、このプロフェッサーを追加しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'shop', 'templates/'), os.path.join(BASE_DIR, 'search_app', 'templates/'), os.path.join(BASE_DIR, 'cart', 'templates/')], 'APP_DIRS': True, 'OPTIONS': { '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を修正します。
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 |
app/shop/templates/navbar.html <nav class="navbar navbar-expand-lg navbar-light bg-light"> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav mr-auto"> <li class="nav-item dropdown {% if 'shop' in request.path %}active{% endif %}"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Shop </a> <div class="dropdown-menu" aria-labelledby="navbarDropdown"> <a class="dropdown-item" href="{% url 'shop:all_product' %}">All Products</a> {% for product in products %} <a class="dropdown-item" href="{{product.get_url}}">{{product.name}}</a> {% endfor %} </div> </li> <li class="nav-item"> <a class="nav-link" href="#"><i class="fas fa-shopping-cart"></i></a> </li> <!-- 追加 --> {% if item_count > 0 %} <li class="nav-item"> <a class="nav-link" href="{% url 'cart:cart_detail' %}">({{item_count}})</a> </li> {% endif %} </ul> <form class="form-inline my-2 my-lg-0" action="{% url 'search:search_result' %}" method="get"> {% csrf_token %} <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" name="q"> <button class="btn btn-secondary my-2 my-sm-0" type="submit"><i class="fas fa-search"></i></button> </form> </div> </nav> |
最後に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 110 111 112 113 114 115 116 117 118 119 120 |
app/cart/templates/cart.html {% extends "base.html" %} {% load staticfiles %} {% block metadescription %} This is the shopping cart page.. Proced 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"> <thead class="my_custom_thead"> <tr> <th colspan="5"> Your items </th> </tr> </thead> <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="{% url 'cart:cart_remove' cart_item.product.id %}" class="custom_a"> <i class="fas fa-minus-circle custom_icon"></i> </a> <a href="{% url 'cart:full_remove' cart_item.product.id %}" class="custom_item"> <i class="far fa-trash-alt"></i> </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"></i> </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 %} </tr> {% endfor %} </tbody> </table> </div> <div class="col-12 col-sm-12 col-lg-6 text-center"> <table class="table my_custom_table"> <thead class="my_custom_thead"> <tr> <th> Checkout </th> </tr> </thead> <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> <br> {% endif %} {% endblock %} |
これで、Todoリストの⑤が消せますね。
動作確認をしましょう。Shopping Cartに商品を追加して、一覧を表示します。

今は、合計7商品入ってますね。バナナの-ボタンをクリックしてみます。
バナナが一つカートから消えましたね。

バナナのバケツボタンをクリックしてみます。

バナナが消えました。アップルのバケツボタンもクリックしてみます。

動作は問題ない様ですね。
参考書籍
終わりに
お疲れ様でした!今回でショッピングカートの開発は終了です!
これだけできれば、色々なDjangoのアプリ開発に挑戦できると思いますよ^^
コメントを残す
コメントを投稿するにはログインしてください。