23、构建游戏商店应用:从价格模型到购物车的实现

构建游戏商店应用:从价格模型到购物车的实现

1. 创建价格列表数据模型

为了实现更改产品价格、记录价格添加时间和最后更新时间的功能,我们将在 gamestore/main/ 目录下的 models.py 文件中创建一个名为 PriceList 的模型类。以下是具体代码:

class PriceList(models.Model):
    added_at = models.DateTimeField(auto_now_add=True)
    last_updated = models.DateTimeField(auto_now=True)
    price_per_unit = models.DecimalField(max_digits=9,
                                         decimal_places=2, 
                                         default=0)
    game = models.OneToOneField(
        Game,
        on_delete=models.CASCADE,
        primary_key=True)
    def __str__(self):
        return self.game.name

在这个模型中:
- added_at 字段:使用 auto_now_add=True ,当向表中添加价格时,Django 会自动添加当前日期。
- last_updated 字段:使用 auto_now=True ,每次更新时,Django 会设置当前日期。
- price_per_unit 字段:定义为 DecimalField ,最多 9 位数字,2 位小数,默认为 0。
- game 字段:使用 OneToOneField Game 对象建立联系,当游戏被删除时, PriceList 表中的相关行也会被删除,并且该字段被定义为主键。
- __str__ 方法:返回游戏的名称,这在使用 Django 管理界面更新价格时很有用。

创建完模型后,我们需要生成并应用迁移文件:

python manage.py makemigrations
python manage.py migrate
2. 创建游戏列表和详情页面

接下来,我们要创建视图和模板来在页面上显示游戏。
- 添加页面内容 :我们已经在 main/templates/main 目录下创建了 index.html 模板,但它目前没有显示任何内容。为了让页面更有趣,我们将添加两部分内容:
1. 页面顶部的一个部分,用于显示我们想要突出显示的游戏,如新店到货的新游戏、非常受欢迎的游戏或价格划算的游戏。
2. 突出显示的游戏部分之后,列出所有其他游戏。

  • 创建部分视图模板 :我们将创建一个部分视图模板 games-list.html 来显示游戏列表,该模板将被所有需要显示游戏列表的模板共享。在 gamestore/main/templates/main/ 目录下创建 games-list.html 文件,内容如下:
{% load staticfiles %}
{% load humanize %}
<div class='game-container'>
    {% for game in gameslist %}
    {% if game.highlighted and highlight_games %}
      <div class='item-box highlighted'>
    {% else %}
      <div class='item-box'>
    {% endif %}
      <div class='item-image'>
      <img src="{% static game.image.url %}"></img>
    </div>
      <div class='item-info'>
        <h3>{{game.name}}</h3>
        <p>Release year: {{game.release_year}}</p>
        <p>Developer: {{game.developer}}</p>
        <p>Publisher: {{game.published_by}}</p>
        {% if game.pricelist.price_per_unit %}
          <p class='price'>
            Price: 
          ${{game.pricelist.price_per_unit|floatformat:2|intcomma}}
          </p>
        {% else %}
        <p class='price'>Price: Not available</p>
        {% endif %}
      </div>
     <a href="/cart/add/{{game.id}}" class="add-to-cart btn
        btn-primary">
       <i class="fa fa-shopping-cart" aria-hidden="true"></i>
       Add to cart
     </a>
   </div>
   {% endfor %}
</div>

注意,我们在页面顶部添加了 {% load humanize %} ,这是 Django 框架内置的一组模板过滤器,用于正确格式化游戏价格。为了使用这些过滤器,我们需要编辑 gamestore/gamestore 目录下的 settings.py 文件,并将 django.contrib.humanize 添加到 INSTALLED_APPS 设置中。

  • 修改 index.html 文件 :将 gamestore/main/templates/main 目录下的 index.html 文件内容替换为以下代码:
{% extends 'base.html' %}
{% block 'content' %}
  {% if highlighted_games_list %}
    <div class='panel panel-success'>
      <div class='panel-heading'>
        <h2 class='panel-title'><i class="fa fa-gamepad"
        aria-hidden="true"></i>Highlighted games</h2>
      </div>
      <div class='panel-body'>
        {% include 'main/games-list.html' with 
         gameslist=highlighted_games_list highlight_games=False%}
        {% if show_more_link_highlighted %}
        <p>
          <a href='/games-list/highlighted/'>See more items</a>
        </p>
        {% endif %}
      </div>
    </div>
  {% endif %}
  {% if games_list %}
    {% include 'main/games-list.html' with gameslist=games_list 
     highlight_games=False%}
    {% if show_more_link_games %}
      <p>
        <a href='/games-list/all/'>See all items</a>
      </p>
    {% endif %}
  {% endif %}
{% endblock %}

在这个代码中,我们使用 {% include %} 标签包含了部分视图模板,并传递了两个参数 gameslist highlight_games

  • 添加 CSS 代码 :编辑 gamestore/static/styles/ 目录下的 site.css 文件,添加以下 CSS 代码:
.game-container {
    margin-top: 10px;
    display:flex;
    flex-direction: row;
    flex-wrap: wrap;
}
.game-container .item-box {
    flex-grow: 0;
    align-self: auto;
    width:339px;
    margin: 0px 10px 20px 10px;
    border: 1px solid #aba5a5;
    padding: 10px;
    background-color: #F0F0F0;
}
.game-container .item-box .add-to-cart {
    margin-top: 15px;
    float: right;
}
.game-container .item-box.highlighted {
    background-color:#d7e7f5;
}
.game-container .item-box .item-image {
    float: left;
}
.game-container .item-box .item-info {
    float: left;
    margin-left: 15px;
    width:100%;
    max-width:170px;
}
.game-container .item-box .item-info p {
    margin: 0 0 3px;
}
.game-container .item-box .item-info p.price {
    font-weight: bold;
    margin-top: 20px;
    text-transform: uppercase;
    font-size: 0.9em;
}
.game-container .item-box .item-info h3 {
    max-width: 150px;
    word-wrap: break-word;
    margin: 0px 0px 10px 0px;
}
  • 修改 index 视图函数 :编辑 gamestore/main/ 目录下的 views.py 文件,修改 index 函数如下:
from .models import Game

def index(request):
    max_highlighted_games = 3
    max_game_list = 9
    highlighted_games_list = Game.objects.get_highlighted()
    games_list = Game.objects.get_not_highlighted()
    show_more_link_promoted = highlighted_games_list.count() > 
    max_highlighted_games
    show_more_link_games = games_list.count() > max_game_list
    context = {
        'highlighted_games_list': 
         highlighted_games_list[:max_highlighted_games],
        'games_list': games_list[:max_game_list],
        'show_more_link_games': show_more_link_games,
        'show_more_link_promoted': show_more_link_promoted
    }
    return render(request, 'main/index.html', context)

在这个函数中,我们首先定义了要显示的每种类型游戏的数量,然后获取推广和非推广游戏,创建两个变量 show_more_link_promoted show_more_link_games 来判断是否显示“查看更多”链接,最后创建上下文变量并调用 render 函数渲染模板。

  • 注册模型到管理界面 :为了创建游戏,我们需要将模型注册到 Django 管理界面。编辑 admin.py 文件,添加以下代码:
from django.contrib import admin
from .models import GamePlatform
from .models import Game
from .models import PriceList
admin.autodiscover()
admin.site.register(GamePlatform)
admin.site.register(Game)
admin.site.register(PriceList)
  • 配置媒体文件路径 :由于我们要为游戏添加图片,需要配置 Django 保存上传图片的位置。编辑 gamestore/gamestore 目录下的 settings.py 文件,在 STATIC_DIRS 设置下方添加以下代码:
MEDIA_ROOT = os.path.join(BASE_DIR, 'static')
  • 创建游戏 :启动网站:
python manage.py runserver

浏览到 http://localhost:8000/admin ,使用我们创建的超级用户账户登录。在管理界面中,先添加游戏平台,然后添加游戏。在添加游戏之前,需要在 gamestore/static/images/ 目录下放置一个名为 placeholder.png 的默认图片,图片大小为 130x180 效果更佳。可以通过 http://via.placeholder.com/130x180 获取合适大小的占位符图片。添加完游戏后,再次访问网站,应该可以在首页看到游戏列表。

3. 添加游戏列表视图

由于我们在首页没有显示所有游戏,需要构建页面来显示所有游戏。
- 创建 URL :在主应用的 url.py 文件中,添加以下两个 URL 到 urlpatterns 列表中:

path(r'games-list/highlighted/', views.show_highlighted_games),
path(r'games-list/all/', views.show_all_games),
  • 创建模板 :在 gamestore/main/templates/main 目录下创建 all_games.html 文件,内容如下:
{% extends 'base.html' %}
{% block 'content' %}
 <h2>Highlighted games</h2>
 <hr/>
 {% if games %}
   {% include 'main/games-list.html' with gameslist=games
        highlight_promoted=False%}
   {% else %}
   <div class='empty-game-list'>
   <h3>There's no promoted games available at the moment</h3>
  </div>
 {% endif %}
 {% endblock %}

再创建 highlighted.html 文件,内容如下:

{% extends 'base.html' %}
{% block 'content' %}
<h2>All games</h2>
<hr/>
{% if games %}
  {% include 'main/games-list.html' with gameslist=games
    highlight_games=True%}
  {% else %}
  <div class='empty-game-list'>
    <h3>There's no promoted games available at the moment</h3>
  </div>
{% endif %}
{% endblock %}
  • 添加视图函数 :编辑 gamestore/main/ 目录下的 views.py 文件,添加以下两个函数:
def show_all_games(request):
    games = Game.objects.all()
    context = {'games': games}
    return render(request, 'main/all_games.html', context)

def show_highlighted_games(request):
    games = Game.objects.get_highlighted()
    context = {'games': games}
    return render(request, 'main/highlighted.html', context)

这两个函数分别获取所有游戏和仅推广游戏的列表,并将其传递给相应的模板进行渲染。

4. 创建购物车模型

目前我们的应用可以显示游戏,但用户无法购买游戏,因此需要实现一个购物车。我们将通过将购物车项目保存到数据库来实现购物车,而不是基于用户会话实现。
购物车的要求如下:
- 用户可以添加任意数量的商品。
- 用户应该能够更改购物车中的商品,例如更改商品数量。
- 可以移除商品。
- 应该有清空购物车的选项。
- 所有数据都应该经过验证。
- 如果拥有购物车的用户被删除,购物车及其项目也应该被删除。

以下是具体的实现步骤:
- 创建 ShoppingCartManager :在 gamestore/main 目录下的 models.py 文件中添加以下代码:

from django.contrib.auth.models import User

class ShoppingCartManager(models.Manager):
    def get_by_id(self, id):
        return self.get(pk=id)
    def get_by_user(self, user):
        return self.get(user_id=user.id)
    def create_cart(self, user):
        new_cart = self.create(user=user)
        return new_cart

这个类包含三个方法:
- get_by_id :根据 ID 获取购物车。
- get_by_user :根据用户实例获取购物车。
- create_cart :当用户创建账户时调用,创建一个新的购物车。

  • 创建 ShoppingCart
class ShoppingCart(models.Model):
    user = models.ForeignKey(User,
                             null=False,
                             on_delete=models.CASCADE)
    objects = ShoppingCartManager()
    def __str__(self):
        return f'{self.user.username}\'s shopping cart'

这个类定义了一个外键 user User 模型关联,当用户被删除时,购物车也会被删除。同时,我们将自定义的 ShoppingCartManager 分配给 objects 属性,并实现了 __str__ 方法,以便在 Django 管理界面中更好地显示购物车信息。

  • 创建 ShoppingCartItemManager
class ShoppingCartItemManager(models.Manager):
    def get_items(self, cart):
        return self.filter(cart_id=cart.id)

这个类只定义了一个方法 get_items ,用于获取购物车中的所有项目。

  • 创建 ShoppingCartItem
class ShoppingCartItem(models.Model):
    quantity = models.IntegerField(null=False)
    price_per_unit = models.DecimalField(max_digits=9,
                                         decimal_places=2,
                                         default=0)
    cart = models.ForeignKey(ShoppingCart,
                             null=False,
                             on_delete=models.CASCADE)
    game = models.ForeignKey(Game,
                             null=False,
                             on_delete=models.CASCADE)
    objects = ShoppingCartItemManager()

这个类定义了两个属性 quantity price_per_unit ,分别表示商品数量和单价。同时,定义了两个外键 cart game ,分别与 ShoppingCart Game 模型关联。将自定义的 ShoppingCartItemManager 分配给 objects 属性。

  • 生成并应用迁移文件 :在终端中运行以下命令:
python manage.py makemigrations
python manage.py migrate

通过以上步骤,我们完成了从价格列表数据模型到购物车模型的创建,为游戏商店应用添加了完整的功能。接下来,我们可以继续为按钮添加功能,实现将商品添加到购物车的功能。

以下是整个流程的 mermaid 流程图:

graph LR
    A[创建价格列表数据模型] --> B[创建游戏列表和详情页面]
    B --> C[添加游戏列表视图]
    C --> D[创建购物车模型]
    A --> E[生成并应用迁移文件]
    B --> E
    C --> E
    D --> E
    E --> F[启动网站并创建游戏]
    F --> G[验证功能]

通过这个流程图,可以清晰地看到整个开发过程的步骤和顺序。

构建游戏商店应用:从价格模型到购物车的实现

5. 为购物车添加功能

现在购物车模型已经创建好,接下来要为“添加到购物车”按钮添加功能,让用户能够将游戏添加到购物车中。

  • 创建添加到购物车的视图函数 :编辑 gamestore/main/ 目录下的 views.py 文件,添加以下函数:
from django.shortcuts import redirect, get_object_or_404
from .models import Game, ShoppingCart, ShoppingCartItem

def add_to_cart(request, game_id):
    game = get_object_or_404(Game, id=game_id)
    user = request.user
    if user.is_authenticated:
        try:
            cart = ShoppingCart.objects.get_by_user(user)
        except ShoppingCart.DoesNotExist:
            cart = ShoppingCart.objects.create_cart(user)
        try:
            cart_item = ShoppingCartItem.objects.get(cart=cart, game=game)
            cart_item.quantity += 1
            cart_item.save()
        except ShoppingCartItem.DoesNotExist:
            cart_item = ShoppingCartItem.objects.create(
                cart=cart,
                game=game,
                quantity=1,
                price_per_unit=game.pricelist.price_per_unit
            )
    return redirect('index')

在这个函数中,首先获取要添加到购物车的游戏对象,然后检查用户是否已登录。如果用户已登录,尝试获取用户的购物车,如果购物车不存在则创建一个新的购物车。接着检查购物车中是否已经存在该游戏的项目,如果存在则增加数量,不存在则创建一个新的购物车项目。最后重定向到首页。

  • 更新 URL 配置 :在主应用的 url.py 文件中,添加以下 URL 到 urlpatterns 列表中:
path('cart/add/<int:game_id>/', views.add_to_cart, name='add_to_cart'),
6. 显示购物车内容

接下来,我们要创建一个页面来显示购物车中的内容。

  • 创建购物车视图函数 :在 gamestore/main/ 目录下的 views.py 文件中添加以下函数:
def view_cart(request):
    user = request.user
    if user.is_authenticated:
        try:
            cart = ShoppingCart.objects.get_by_user(user)
            cart_items = ShoppingCartItem.objects.get_items(cart)
            total_price = sum(item.quantity * item.price_per_unit for item in cart_items)
        except ShoppingCart.DoesNotExist:
            cart_items = []
            total_price = 0
    else:
        cart_items = []
        total_price = 0
    context = {
        'cart_items': cart_items,
        'total_price': total_price
    }
    return render(request, 'main/cart.html', context)

在这个函数中,首先检查用户是否已登录。如果用户已登录,获取用户的购物车和购物车中的项目,并计算购物车的总价。如果用户未登录,则购物车项目和总价都设为 0。最后将购物车项目和总价传递给模板进行渲染。

  • 创建购物车模板 :在 gamestore/main/templates/main/ 目录下创建 cart.html 文件,内容如下:
{% extends 'base.html' %}
{% block 'content' %}
  <h2>Shopping Cart</h2>
  <hr/>
  {% if cart_items %}
    <table class="table">
      <thead>
        <tr>
          <th>Game</th>
          <th>Quantity</th>
          <th>Price per Unit</th>
          <th>Total Price</th>
          <th>Action</th>
        </tr>
      </thead>
      <tbody>
        {% for item in cart_items %}
          <tr>
            <td>{{ item.game.name }}</td>
            <td>{{ item.quantity }}</td>
            <td>${{ item.price_per_unit|floatformat:2|intcomma }}</td>
            <td>${{ item.quantity * item.price_per_unit|floatformat:2|intcomma }}</td>
            <td>
              <a href="{% url 'remove_from_cart' item.id %}" class="btn btn-danger">Remove</a>
            </td>
          </tr>
        {% endfor %}
        <tr>
          <td colspan="3"><strong>Total:</strong></td>
          <td><strong>${{ total_price|floatformat:2|intcomma }}</strong></td>
          <td></td>
        </tr>
      </tbody>
    </table>
  {% else %}
    <p>Your cart is empty.</p>
  {% endif %}
{% endblock %}

在这个模板中,使用表格显示购物车中的项目,包括游戏名称、数量、单价、总价和移除按钮。如果购物车为空,则显示提示信息。

  • 更新 URL 配置 :在主应用的 url.py 文件中,添加以下 URL 到 urlpatterns 列表中:
path('cart/view/', views.view_cart, name='view_cart'),
7. 实现移除购物车项目功能

为了让用户能够移除购物车中的项目,我们需要实现移除功能。

  • 创建移除购物车项目的视图函数 :在 gamestore/main/ 目录下的 views.py 文件中添加以下函数:
def remove_from_cart(request, cart_item_id):
    cart_item = get_object_or_404(ShoppingCartItem, id=cart_item_id)
    cart_item.delete()
    return redirect('view_cart')

在这个函数中,首先获取要移除的购物车项目对象,然后将其从数据库中删除,最后重定向到购物车页面。

  • 更新 URL 配置 :在主应用的 url.py 文件中,添加以下 URL 到 urlpatterns 列表中:
path('cart/remove/<int:cart_item_id>/', views.remove_from_cart, name='remove_from_cart'),
8. 优化用户体验

为了提升用户体验,我们可以做一些优化。

  • 添加导航栏链接 :在 base.html 模板中添加购物车和添加到购物车的链接,让用户可以方便地访问购物车和添加游戏到购物车。
<nav class="navbar navbar-default">
  <div class="container-fluid">
    <div class="navbar-header">
      <a class="navbar-brand" href="{% url 'index' %}">Game Store</a>
    </div>
    <ul class="nav navbar-nav">
      {% if user.is_authenticated %}
        <li><a href="{% url 'view_cart' %}">View Cart</a></li>
      {% endif %}
    </ul>
  </div>
</nav>
  • 错误处理和提示信息 :在视图函数中添加更多的错误处理和提示信息,让用户在操作出现问题时能够得到明确的反馈。例如,在添加到购物车时,如果游戏价格不可用,可以显示提示信息。

以下是整个购物车功能实现的步骤表格:
| 步骤 | 操作 | 代码文件 | 代码内容 |
| ---- | ---- | ---- | ---- |
| 1 | 创建添加到购物车视图函数 | views.py | add_to_cart 函数 |
| 2 | 更新 URL 配置 | url.py | path('cart/add/<int:game_id>/', views.add_to_cart, name='add_to_cart') |
| 3 | 创建购物车视图函数 | views.py | view_cart 函数 |
| 4 | 创建购物车模板 | cart.html | 购物车模板代码 |
| 5 | 更新 URL 配置 | url.py | path('cart/view/', views.view_cart, name='view_cart') |
| 6 | 创建移除购物车项目视图函数 | views.py | remove_from_cart 函数 |
| 7 | 更新 URL 配置 | url.py | path('cart/remove/<int:cart_item_id>/', views.remove_from_cart, name='remove_from_cart') |
| 8 | 优化用户体验 | base.html | 添加导航栏链接 |

以下是购物车功能实现的 mermaid 流程图:

graph LR
    A[用户点击添加到购物车按钮] --> B{用户是否登录}
    B -- 是 --> C{购物车是否存在}
    C -- 是 --> D{购物车中是否已有该游戏}
    D -- 是 --> E[增加数量]
    D -- 否 --> F[创建新购物车项目]
    C -- 否 --> F
    B -- 否 --> G[提示用户登录]
    H[用户点击查看购物车] --> I{用户是否登录}
    I -- 是 --> J[显示购物车内容]
    I -- 否 --> K[提示用户登录]
    L[用户点击移除购物车项目] --> M[移除项目]
    M --> J

通过以上步骤,我们完成了游戏商店应用从价格模型到购物车功能的实现,并且对用户体验进行了优化。现在用户可以方便地浏览游戏、将游戏添加到购物车、查看购物车内容和移除购物车项目。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值