六、商品详情页
6.1 商品详情页分析和准备
6.1.1. 商品详情页组成结构分析
1.商品频道分类
- 已经提前封装在
contents.utils.py
文件中,直接调用方法即可。
2.面包屑导航
- 已经提前封装在
goods.utils.py
文件中,直接调用方法即可。
3.热销排行
- 该接口已经在商品列表页中实现完毕,前端直接调用接口即可。
4.商品SKU信息(详情信息)
- 通过
sku_id
可以找到SKU信息,然后渲染模板即可。 - 使用Ajax实现局部刷新效果。
5.SKU规格信息
- 通过
SKU
可以找到SPU规格和SKU规格信息。
6.商品详情介绍、规格与包装、售后服务
- 通过
SKU
可以找到SPU
信息,SPU
中可以查询出商品详情介绍、规格与包装、售后服务。
7.商品评价
- 商品评价需要在生成了订单,对订单商品进行评价后再实现,商品评价信息是动态数据。
- 使用Ajax实现局部刷新效果。
6.1.2. 商品详情页接口设计和定义
1.请求方式
选项方案
请求方法
GET
请求地址
/detail/(?P
# 商品详情
url(r'^detail/(?P\d+)/$', views.DetailView.as_view(), name='detail'),
2.请求参数:路径参数
参数名类型是否必传说明
sku_id
string是商品SKU编号
3.响应结果:HTML
detail.html
4.接口定义
goods.views.py
class DetailView(View):
"""商品详情页"""
def get(self, request, sku_id):
"""提供商品详情页"""
return render(request, 'detail.html')
6.1.3. 商品详情页初步渲染
渲染商品频道分类、面包屑导航、商品热销排行
- 将原先在商品列表页实现的代码拷贝到商品详情页即可。
- 添加
detail.js
class DetailView(View):
"""商品详情页"""
def get(self, request, sku_id):
"""提供商品详情页"""
# 获取当前sku的信息
try:
sku = models.SKU.objects.get(id=sku_id)
except models.SKU.DoesNotExist:
return render(request, '404.html')
# 查询商品频道分类
categories = get_categories()
# 查询面包屑导航
breadcrumb = get_breadcrumb(sku.category)
# 渲染页面
context = {
'categories':categories,
'breadcrumb':breadcrumb,
'sku':sku,
}
return render(request, 'detail.html', context)
提示:为了让前端在获取商品热销排行数据时,能够拿到商品分类ID,我们将商品分类ID从模板传入到Vue.js
let category_id = "{{ sku.category.id }}";
data: {
category_id: category_id,
},
6.2 展示详情页数据
6.2.1. 查询和渲染SKU详情信息
渲染页面
context = {
'categories':categories,
'breadcrumb':breadcrumb,
'sku':sku,
}
return render(request, 'detail.html', context)
{{ sku.name }}
{{ sku.caption }}
¥{{ sku.price }}
18人评价
数 量:
+
-
{#...商品规格...#}
总价:[[ sku_amount ]]元
加入购物车
提示:为了实现用户选择商品数量的局部刷新效果,我们将商品单价从模板传入到Vue.js
let sku_price = "{{ sku.price }}";
data: {
sku_price: sku_price,
},
6.2.2. 查询和渲染SKU规格信息
1.查询SKU规格信息
class DetailView(View):
"""商品详情页"""
def get(self, request, sku_id):
"""提供商品详情页"""
# 获取当前sku的信息
try:
sku = models.SKU.objects.get(id=sku_id)
except models.SKU.DoesNotExist:
return render(request, '404.html')
# 查询商品频道分类
categories = get_categories()
# 查询面包屑导航
breadcrumb = get_breadcrumb(sku.category)
# 构建当前商品的规格键
sku_specs = sku.specs.order_by('spec_id')
sku_key = []
for spec in sku_specs:
sku_key.append(spec.option.id)
# 获取当前商品的所有SKU
skus = sku.spu.sku_set.all()
# 构建不同规格参数(选项)的sku字典
spec_sku_map = {}
for s in skus:
# 获取sku的规格参数
s_specs = s.specs.order_by('spec_id')
# 用于形成规格参数-sku字典的键
key = []
for spec in s_specs:
key.append(spec.option.id)
# 向规格参数-sku字典添加记录
spec_sku_map[tuple(key)] = s.id
# 获取当前商品的规格信息
goods_specs = sku.spu.specs.order_by('id')
# 若当前sku的规格信息不完整,则不再继续
if len(sku_key) < len(goods_specs):
return
for index, spec in enumerate(goods_specs):
# 复制当前sku的规格键
key = sku_key[:]
# 该规格的选项
spec_options = spec.options.all()
for option in spec_options:
# 在规格参数sku字典中查找符合当前规格的sku
key[index] = option.id
option.sku_id = spec_sku_map.get(tuple(key))
spec.spec_options = spec_options
# 渲染页面
context = {
'categories':categories,
'breadcrumb':breadcrumb,
'sku':sku,
'specs': goods_specs,
}
return render(request, 'detail.html', context)
2.渲染SKU规格信息
{% for spec in specs %}
{{ spec.name }}:
{% for option in spec.spec_options %}
{% if option.sku_id == sku.id %}
{{ option.value }}
{% elif option.sku_id %}
{{ option.value }}
{% else %}
{{ option.value }}
{% endif %}
{% endfor %}
{% endfor %}
6.2.3. 查询和渲染详情、包装和售后信息
商品详情、包装和售后信息被归类到商品SPU中,
sku.spu
关联查询就可以找到该SKU
的SPU
信息。
商品详情
规格与包装
售后服务
商品评价(18)
商品详情:
{{ sku.spu.desc_detail|safe }}
规格与包装:
{{ sku.spu.desc_pack|safe }}
售后服务:
{{ sku.spu.desc_service|safe }}
{#...商品评价...#}
6.3 统计分类商品访问量
提示:
- 统计分类商品访问量 是统计一天内该类别的商品被访问的次数。
- 需要统计的数据,包括商品分类,访问次数,访问时间。
- 一天内,一种类别,统计一条记录。
6.3.1. 统计分类商品访问量模型类
模型类定义在 goods.models.py
中,然后完成迁移建表。
class GoodsVisitCount(BaseModel):
"""统计分类商品访问量模型类"""
category = models.ForeignKey(GoodsCategory, on_delete=models.CASCADE, verbose_name='商品分类')
count = models.IntegerField(verbose_name='访问量', default=0)
date = models.DateField(auto_now_add=True, verbose_name='统计日期')
class Meta:
db_table = 'tb_goods_visit'
verbose_name = '统计分类商品访问量'
verbose_name_plural = verbose_name
【之前操作中修改了模型中的default_image_url的属性值,导致出现下面的错误】
解决办法:【参考博文:https://www.cnblogs.com/erhangboke/p/11660133.html】
6.3.2. 统计分类商品访问量后端逻辑
1.请求方式
选项方案
请求方法
POST
请求地址
/detail/visit/(?P
# 统计商品的访问量
url(r'^detail/visit/(?P\d+)/$', views.DetailVisitView.as_view()),
2.请求参数:路径参数
参数名类型是否必传说明
category_id
string是商品分类ID,第三级分类
3.响应结果:JSON
字段说明
code
状态码
errmsg
错误信息
4.后端接口定义和实现,
- 如果访问记录存在,说明今天不是第一次访问,不新建记录,访问量直接累加。
- 如果访问记录不存在,说明今天是第一次访问,新建记录并保存访问量。
from django.utils import timezone
from datetime import datetime
import logging
日志统计器
logger = logging.getLogger('django')
Create your views here.
class DetailVisitView(View):
"""详情页分类商品访问量"""
def post(self, request, category_id):
"""记录分类商品访问量"""
try:
category = GoodsCategory.objects.get(id=category_id)
except GoodsCategory.DoesNotExist:
return http.HttpResponseForbidden('缺少必传参数')
# 获取今天的日期
t = timezone.localtime()
today_str = '%d-%02d-%02d' % (t.year, t.month, t.day)
today_date = datetime.strptime(today_str, '%Y-%m-%d')
try:
# 查询今天该类别的商品的访问量
counts_data = category.goodsvisitcount_set.get(date=today_date)
except GoodsVisitCount.DoesNotExist:
# 如果该类别的商品在今天没有过访问记录,就新建一个访问记录
counts_data = GoodsVisitCount()
try:
counts_data.category = category
counts_data.count += 1
counts_data.save()
except Exception as e:
logger.error(e)
return http.HttpResponseServerError('服务器异常')
return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})
Original: https://blog.csdn.net/weixin_44799217/article/details/118642066
Author: IT之一小佬
Title: 美多商城之商品(商品详情页)
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/736529/
转载文章受原作者版权保护。转载请注明原作者出处!