一、商品详情页分析
- 通过页面分析,主要有以下7大功能
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实现局部刷新效果。
二、商品详情页
- 点击商品列表页面中某个商品时,会进入商品详情页面
1、商品列表页面完善
- 商品列表前端页面中跳转页面需要修改
2、接口设计与定义
2.1 请求方式
选项 | 方案 |
---|---|
请求方法 | GET |
请求地址 | /detail/(?P<sku_id>\d+)/ |
2.2 请求参数 : 路径参数 和 查询参数
参数名 | 类型 | 是否必传 | 说明 |
---|---|---|---|
sku_id | string | 是 | 商品SKU编号 |
2.3 响应结果 : HTML
detail.html
2.4 接口定义
class DetailView(View):
"""商品详情页"""
def get(self, request, sku_id):
"""提供商品详情页"""
return render(request, 'detail.html')
2.5 路由定义
3、商品详情页初步渲染
3.1 校验参数、渲染商品频道分类、面包屑导航
- 校验参数
- 校验sku_id是否存在
- 渲染商品频道分类、面包屑导航
- 将原先在商品列表页实现的代码拷贝到商品详情页即可。
- 面包屑导航原参数是商品分类,可通过SKU的外键category获取category对象
- html中,商品频道分类、面包屑导航不变,商品详情页面都是该商品的sku信息,将sku传到前端
def get(self,request,sku_id):
"""提供商品详情页"""
# 校验参数:sku_id
try:
sku=SKU.objects.get(id=sku_id)
except Exception as e:
return render(request,"404.html")
# 查询商品频道分类
categories = get_categories()
# 查询面包屑导航
breadcrumb = get_breadcrumb(sku.category)
content={
'categories': categories, # 商品频道分类
'breadcrumb': breadcrumb, # 面包屑导航
'sku':sku, # 商品sku
}
return render(request,"detail.html")
3.2 添加商品热销排行
- 商品热销排行是前端通过Ajax访问
- 后端实现已封装HotGoodsView()中
- 修改前端相应模块即可
- /templates/detail.html
<div class="new_goods">
<h3>热销排行</h3>
<ul>
<li v-for="sku in hot_skus">
<a href="{% url 'goods:detail' sku.id %}"><img :src="sku.default_image_url"></a>
<h4><a href="{% url 'goods:detail' sku.id %}">[[ sku.name ]]</a></h4>
<div class="price">¥[[ sku.price ]]</div>
</li>
</ul>
</div>
- /static/js/detail.js
// 获取热销商品数据
get_hot_skus(){
if (this.category_id) {
let url = '/hot/'+ this.category_id +'/';
axios.get(url, {
responseType: 'json'
})
.then(response => {
this.hot_skus = response.data.hot_skus;
for(let i=0; i<this.hot_skus.length; i++){
this.hot_skus[i].url = '/detail/' + this.hot_skus[i].id + '/';
}
})
.catch(error => {
console.log(error.response);
})
}
},
- 为了让前端在获取商品热销排行数据时,能够拿到商品分类ID,我们将商品分类ID从模板传入到Vue.js
3.3 修改名称、标题、单价
3.4 修改总价
- 总价通过vue计算得到
- data中定义sku_amount
- 通过监听商品数量量变化,计算总价
- 需要接收后端传递的参数,获取单价
4、查询SKU规格信息后端实现
- 不同商品的规格名称和规格信息可能不同, 即不同商品SPU的规格名称和规格选详不同
- 如衣服规格名称可能有:尺寸编码、颜色、款式等,尺寸编码信息可能有 S、M、L、XL、XXL、XXXL等
- 手机规格名称 可能有:屏幕大小、颜色等,屏幕大小信息可能:5.5 、6.3 等
- 同一商品SPU中,不同规格之间,SKU也可能不同
- 同一款手机spu_id=2 : 规格名称和信息:内存(64G、256G)、颜色(金色、深空灰色、银色)
- 选择(64G , 金色) sku_id=3 , 选择 (256G ,金色) sku_id= 4 …
- 进入详情页面时,SKU_id已明确,需要在规格选项中确定其默认值
- 当选择其它规格选项时,sku_id可能发生变化
4.1 获取当前商品的默认规格选项列表
# 构建当前商品的规格信息id的列表 当前sku id为3的默认的规格
sku_specs = SKUSpecification.objects.filter(sku__id=sku_id).order_by('spec_id')
print("sku_specs.query=",sku_specs.query)
# sku_specs.query= SELECT `tb_sku_specification`.`id`, `tb_sku_specification`.`create_time`, `tb_sku_specification`.`update_time`, `tb_sku_specification`.`sku_id`, `tb_sku_specification`.`spec_id`, `tb_sku_specification`.`option_id` FROM `tb_sku_specification` WHERE `tb_sku_specification`.`sku_id` = 1 ORDER BY `tb_sku_specification`.`spec_id` ASC
sku_key = []
for spec in sku_specs:
sku_key.append(spec.option.id)
# sku_id=3 时 sku_key= [8, 11]
4.2 构建当前商品SPU下不同规格参数(选项)的sku字典
- 获取当前sku_id的商品SPU的 id :spu_id
- 查询id = sup_id 的所有SKU商品集
- 循环取出SKU商品集
- 根据商品sku 取出 SKU规格集
- 将该sku商品的所有规格id组成列表
- 将此列表转换成元组,做为spec_sku_map字典的key,把该商品sku_id作为value
- 当前sku_id的商品SPU相同的一个字典,该字典对应关系是 sku规格集 : sku_id
- 目的是选择不同的商品规格组合时,可以确定该规格对应的sku_id
# 获取当前商品的所有SKU
spu_id = sku.spu_id
skus = SKU.objects.filter(spu_id=spu_id)
# 构建不同规格参数(选项)的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
# spec_sku_map= {(8, 11): 3, (8, 12): 4, (9, 11): 5, (9, 12): 6, (10, 11): 7, (10, 12): 8}
4.3 为前端渲染提供数据
- 获取当前商品SPU规格名称集goods_specs
- 对SPU规格名称集goods_specs进行循环
- 对过enumerate()对数据集进行编号
- 将sku_key的值,赋值给key
- 取出该SPU的规格信息集spec_options
- 循环遍历规格信息集spec_options
- 将规格替换 key[当前编号]的值
- 给当格信息集spec_options中当前对象添加sku_id属性,并将获取SPU下不同规格参数(选项)的sku字典中对的sku_id
- 将 spec_options对象添加为规格名称集goods_specs的spec_options属性
# 获取当前商