Django项目实践(商城):十七、商品详情页面

在这里插入图片描述

(根据居然老师直播课内容整理)

一、商品详情页分析

在这里插入图片描述

  • 通过页面分析,主要有以下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属性
        # 获取当前商品的规格信息
        goods_specs = SPUSpecification.objects.filter(spu_id=spu_id).order_by('id')
        print("goods_specs=",goods_specs)
        # 若当前sku的规格信息不完整,则不再继续
        # if len(sku_key) < len(goods_specs):
        #     return

        for index, spec in enumerate(goods_specs):
            print("index, spec = ",index, spec)
            # 复制当前sku的规格键
            key = sku_key[:]
            # 该规格的选项
            spec_options = spec.options.all()
            print("spec_options=",spec_options)
            print("*****************spec_options.query=",spec_options.query)
            for option in spec_options:
                print("option=",option)
                # 在规格参数sku字典中查找符合当前规格的sku
                print("key=",key)
                key[index] = option.id
                print("key[index]=",key[index],"index=",index,"option.id=",option.id,"key=",key)
                # [1,4,7]
                option.sku_id = spec_sku_map.get(tuple(key))
                print("option.sku_id=",option.sku_id,"tuple(key=",tuple(key),"key=",key)
                print("-"*10)
            spec.spec_options = spec_options
            print("spec.spec_options=",spec.spec_options,"spec_options=",spec_options)

        for index, spec in enumerate(goods_specs):
            print(spec.spec_options.query)
            for option in spec.spec_options:
                print("option.sku_id=",option.sku_id)
                print("option.id=", option.id,"option.value=",option.value)
            print("*"*20)

- 调试信息
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= [1, 4, 7]
spec_sku_map= {
    
    (1, 4, 7): 1, (1, 3, 7): 2}
goods_specs= <QuerySet [<SPUSpecification: Apple MacBook Pro 笔记本: 屏幕尺寸>, <SPUSpecification: Apple MacBook Pro 笔记本: 颜色>, <SPUSpecification: Apple MacBook Pro 笔记本: 版本>]>
goods_specs.query= SELECT `tb_spu_specification`.`id`, `tb_spu_specification`.`create_time`, `tb_spu_specification`.`update_time`, `tb_spu_specification`.`spu_id`, `tb_spu_specification`.`name` FROM `tb_spu_specification` WHERE `tb_spu_specification`.`spu_id` = 1 ORDER BY `tb_spu_specification`.`id` ASC
for enumerate(goods_specs) begin--------------------------------------------------
index, spec =  0 Apple MacBook Pro 笔记本: 屏幕尺寸
type(index), type(spec) =  <class 'int'> <class 'goods.models.SPUSpecification'>
key= [1, 4, 7] sku_key= [1, 4, 7]
spec_options= <QuerySet [<SpecificationOption: Apple MacBook Pro 笔记本: 屏幕尺寸 - 13.3英寸>, <SpecificationOption: Apple MacBook Pro 笔记本: 屏幕尺寸 - 15.4英寸>]>
*****************spec_options.query= SELECT `tb_specification_option`.`id`, `tb_specification_option`.`create_time`, `tb_specification_option`.`update_time`, `tb_specification_option`.`spec_id`, `tb_specification_option`.`value` FROM `tb_specification_option` WHERE `tb_specification_option`.`spec_id` = 1
option= Apple MacBook Pro 笔记本: 屏幕尺寸 - 13.3英寸
key= [1, 4, 7]
key[index]= 1 index= 0 option.id= 1 key= [1, 4, 7]
option.sku_id= 1 tuple(key= (1, 4, 7) key= [1, 4, 7]
----------
option= Apple MacBook Pro 笔记本: 屏幕尺寸 - 15.4英寸
key= [1, 4, 7]
key[index]= 2 index= 0 option.id= 2 key= [2, 4, 7]
option.sku_id= None tuple(key= (2, 4, 7) key= [2, 4, 7]
----------
spec.spec_options= <QuerySet [<SpecificationOption: Apple MacBook Pro 笔记本: 屏幕尺寸 - 13.3英寸>, <SpecificationOption: Apple MacBook Pro 笔记本: 屏幕尺寸 - 15.4英寸>]> spec_options= <QuerySet [<SpecificationOption: Apple MacBook Pro 笔记本: 屏幕尺寸 - 13.3英寸>, <SpecificationOption: Apple MacBook Pro 笔记本: 屏幕尺寸 - 15.4英寸>]>
for enumerate(goods_specs) end--------------------------------------------------
for enumerate(goods_specs) begin--------------------------------------------------
index, spec =  1 Apple MacBook Pro 笔记本: 颜色
type(index), type(spec) =  <class 'int'> <class 'goods.models.SPUSpecification'>
key= [1, 4, 7] sku_key= [1, 4, 7]
spec_options= <QuerySet [<SpecificationOption: Apple MacBook Pro 笔记本: 颜色 - 深灰色>, <SpecificationOption: Apple MacBook Pro 笔记本: 颜色 - 银色>]>
*****************spec_options.query= SELECT `tb_specification_option`.`id`, `tb_specification_option`.`create_time`, `tb_specification_option`.`update_time`, `tb_specification_option`.`spec_id`, `tb_specification_option`.`value` FROM `tb_specification_option` WHERE `tb_specification_option`.`spec_id` = 2
option= Apple MacBook Pro 笔记本: 颜色 - 深灰色
key= [1, 4, 7]
key[index]= 3 index= 1 option.id= 3 key= [1, 3, 7]
option.sku_id= 2 tuple(key= (1, 3, 7) key= [1, 3, 7]
----------
option= Apple MacBook Pro 笔记本: 颜色 - 银色
key= [1, 3, 7]
key[index]= 4 index= 1 option.id= 4 key= [1, 4, 7]
option.sku_id= 1 tuple(key= (1, 4, 7) key= [1, 4, 7]
----------
spec.spec_options= <QuerySet [<SpecificationOption: Apple MacBook Pro 笔记本: 颜色 - 深灰色>, <SpecificationOption: Apple MacBook Pro 笔记本: 颜色 - 银色>]> spec_options= <QuerySet [<SpecificationOption: Apple MacBook Pro 笔记本: 颜色 - 深灰色>, <SpecificationOption: Apple MacBook Pro 笔记本: 颜色 - 银色>]>
for enumerate(goods_specs) end--------------------------------------------------
for enumerate(goods_specs) begin--------------------------------------------------
index, spec =  2 Apple MacBook Pro 笔记本: 版本
type(index), type(spec) =  <class 'int'> <class 'goods.models.SPUSpecification'>
key= [1, 4, 7] sku_key= [1, 4, 7]
spec_options= <QuerySet [<SpecificationOption: Apple MacBook Pro 笔记本: 版本 - core i5/8G内存/256G存储>, <SpecificationOption: Apple MacBook Pro 笔记本: 版本 - core i5/8G内存/128G存储>, <SpecificationOption: Apple MacBook Pro 笔记本: 版本 - core i5/8G内存/512G存储>]>
*****************spec_options.query= SELECT `tb_specification_option`.`id`, `tb_specification_option`.`create_time`, `tb_specification_option`.`update_time`, `tb_specification_option`.`spec_id`, `tb_specification_option`.`value` FROM `tb_specification_option` WHERE `tb_specification_option`.`spec_id` = 3
option= Apple MacBook Pro 笔记本: 版本 - core i5/8G内存/256G存储
key= [1, 4, 7]
key[index]= 5 index= 2 option.id= 5 key= [1, 4, 5]
option.sku_id= None tuple(key= (1, 4, 5) key= [1, 4, 5]
----------
option= Apple MacBook Pro 笔记本: 版本 - core i5/8G内存/128G存储
key= [1, 4, 5]
key[index]= 6 index= 2 option.id= 6 key= [1, 4, 6]
option.sku_id= None tuple(key= (1, 4, 6) key= [1, 4, 6]
----------
option= Apple MacBook Pro 笔记本: 版本 - core i5/8G内存/512G存储
key= [1, 4, 6]
key[index]= 7 index= 2 option.id= 7 key= [1, 4, 7]
option.sku_id= 1 tuple(key= (1, 4, 7) key= [1, 4, 7]
----------
spec.spec_options= <QuerySet [<SpecificationOption: Apple MacBook Pro 笔记本: 版本 - core i5/8G内存/256G存储>, <SpecificationOption: Apple MacBook Pro 笔记本: 版本 - core i5/8G内存/128G存储>, <SpecificationOption: Apple MacBook Pro 笔记本: 版本 - core i5/8G内存/512G存储>]> spec_options= <QuerySet [<SpecificationOption: Apple MacBook Pro 笔记本: 版本 - core i5/8G内存/256G存储>, <SpecificationOption: Apple MacBook Pro 笔记本: 版本 - core i5/8G内存/128G存储>, <SpecificationOption: Apple MacBook Pro 笔记本: 版本 - core i5/8G内存/512G存储>]>
for enumerate(goods_specs) end--------------------------------------------------
SELECT `tb_specification_option`.`id`, `tb_specification_option`.`create_time`, `tb_specification_option`.`update_time`, `tb_specification_option`.`spec_id`, `tb_specification_option`.`value` FROM `tb_specification_option` WHERE `tb_specification_option`.`spec_id` = 1
option.sku_id= 1
option.id= 1 option.value= 13.3英寸
option.sku_id= None
option.id= 2 option.value= 15.4英寸
********************
SELECT `tb_specification_option`.`id`, `tb_specification_option`.`create_time`, `tb_specification_option`.`update_time`, `tb_specification_option`.`spec_id`, `tb_specification_option`.`value` FROM `tb_specification_option` WHERE `tb_specification_option`.`spec_id` = 2
option.sku_id= 2
option.id= 3 option.value= 深灰色
option.sku_id= 1
option.id= 4 option.value= 银色
********************
SELECT `tb_specification_option`.`id`, `tb_specification_option`.`create_time`, `tb_specification_option`.`update_time`, `tb_specification_option`.`spec_id`, `tb_specification_option`.`value` FROM `tb_specification_option` WHERE `tb_specification_option`.`spec_id` = 3
option.sku_id= None
option.id= 5 option.value= core i5/8G内存/256G存储
option.sku_id= None
option.id= 6 option.value= core i5/8G内存/128G存储
option.sku_id= 1
option.id= 7 option.value= core i5/8G内存/512G存储
********************

5、前端实现

5.1 前端接收数据

  • 后端传递的参数
    在这里插入图片描述
  • categories : 商品分类栏 展示的地方接收,并渲染
  • breadcrumb:面包屑导航展示的地方接收,并渲染
  • goods_specs:商品规格信息展示的地方接收,并渲染
   	specs = [
   		{
    
    
   	        'name': '颜色',
   	        'options': [
   	            {
    
    'value': '金色', 'sku_id': 'xxxx'},
   	            {
    
    'value': '深空灰', 'sku_id': 'xxxx'},
   	            {
    
    'value': '银色', 'sku_id': 'xxxx'}
   			]
   		},
   		{
    
    
   	    	'name': '内存',
   	    	'options': [
   	        	{
    
    'value': '64GB', 'sku_id': 'xxxx'},
   	        	{
    
    'value': '256GB', 'sku_id': 'xxxx'}
   	    	]
   	    }
   	]
  • sku: 多个地方使用,
    • 商品名称、副标题、单价等地方直接使用属性
    • 取sku属性赋值变量,供vue使用
      在这里插入图片描述

5.2 商品规格渲染

在这里插入图片描述

  • 循环遍历specs (即后端 goods_specs,SPU规格信息集,添加过属性)
    • 显示 SPU规格名称
    • 循环遍历spec_options
    • 判断 option.sku_id(添加的属性)是否等于当前商品的sku_id
    • 如果相等,商品规格信息的名称无跳转链接
    • 否则判断 option.sku_id不为空,商品规格信息的名称有跳转链接:跳转到sku_id=option.sku_id的详情页面
    • 否则(该商品属性组合,无sku_id) 商品规格信息的名称无跳转链接

三、统计分类商品访问量

  • 进入商品详情页面时,会发起统计分类商品访问量

1、定义商品访问量表

  • 需要sku_id、count
  • 如果按天统计访问量,需要日期,如果需求按月统计,此处可以改成月
  • user 可选项,用户登录可以记,用户未登录,无法区分
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

2、接口设计与定义

2.1 请求方式

选项 方案
请求方法 POST
请求地址 /detail/visit/(?P<category_id>\d+)/

2.2 请求参数 : 路径参数 和 查询参数

参数名 类型 是否必传 说明
category_id string 商品分类ID,第三级分类

2.3 响应结果 : JSON

响应结果 响应内容
code 状态码
errmsg 错误信息

2.4 路由定义

在这里插入图片描述

3、后端view实现

  • 校验参数sku_id
    • 通过GoodsCategory获得id=category_id的对象category
  • 获取当前的日期
  • 将当前日期格式化成字符串
  • 通过GoodsVisitCount得到date=当前日期字符串,category=category.id的对象counts_data
  • 如果不存在,创建空的counts_data对象
  • counts_data的category属性赋值 category
  • counts_data的count自加1
  • counts_data的日期赋值当前日期字符串
  • 保存数据
  • 返回前端响应结果
class DetailVisitView(View):
    """统计分类商品的访问量"""

    def post(self, request, category_id):
        # 校验参数
        try:
            category = GoodsCategory.objects.get(id=category_id)
        except Exception as e:
            return http.HttpResponseForbidden('category_id不存在')
        # 获取当前的日期
        t = timezone.localtime()
        # print(t)    2021-03-26 13:29:58.365797+00:00
        # 获取当前的时间字符串
        today_str = '%d-%02d-%02d' % (t.year, t.month, t.day)

        try:
            # 存在记录  修改记录 count
            counts_data = GoodsVisitCount.objects.get(date=today_str, category=category.id)
        except GoodsVisitCount.DoesNotExist:
            # 不存在记录 新增
            counts_data = GoodsVisitCount()

        # 保存  count  category_id  time  user(可选)
        try:
            counts_data.category = category
            counts_data.count += 1
            counts_data.date = today_str
            counts_data.save()
        except Exception as e:
            return http.HttpResponseServerError('统计失败')

        # 响应结果
        return http.JsonResponse({
    
    'code': RETCODE.OK, 'errmsg': 'OK'})

4.注意事项

4.1 注意修改Django参数中的时区

4.2 objects.filter() 没有 DoesNotExist 异常,但get有

在这里插入图片描述
在这里插入图片描述

四、用户浏览记录保存与展示

  • 当登录用户在浏览商品的详情页时,我们就可以把详情页这件商品信息存储起来,作为该登录用户的浏览记录。
  • 用户未登录,我们不记录其商品浏览记录。

1、用户浏览记录存储方案

在这里插入图片描述

1.1 存储数据说明

  • 虽然浏览记录界面上要展示商品的一些SKU信息,但是我们在存储时没有必要存很多SKU信息。
  • 我们选择存储SKU信息的唯一编号(sku_id)来表示该件商品的浏览记录。
  • 存储数据:sku_id

1.2 存储位置说明

  • 用户浏览记录是临时数据,且经常变化,数据量不大,所以我们选择内存型数据库进行存储。
  • 户浏览记录数据无需长久保存,并且保存失败也无关紧要
  • 存储位置:Redis数据库 3号库

1.3 存储类型说明

  • 由于用户浏览记录跟用户浏览商品详情的顺序有关,所以我们选择使用Redis中的list类型存储 sku_id
  • 每个用户维护一条浏览记录,且浏览记录都是独立存储的,不能共用。所以我们需要对用户的浏览记录进行唯一标识。
  • 我们可以使用登录用户的ID来唯一标识该用户的浏览记录。
  • 存储类型:‘history_user_id’ : [sku_id_1, sku_id_2, …]

1.4 存储逻辑说明

  • SKU信息不能重复。
  • 最近一次浏览的商品SKU信息排在最前面,以此类推。
  • 每个用户的浏览记录最多存储五个商品SKU信息。
  • 存储逻辑:先去重,再存储,最后截取。

2、保存用户浏览记录

  • 当用户点击商品详情页时,提交用户浏览记录(sku),后台进行保存

2.1 请求方式

选项 方案
请求方法 POST
请求地址 /users/browse_histories/

2.2 请求参数 : JSON

参数名 类型 是否必传 说明
sku_id string 商品SKU编号

2.3 响应结果 : JSON

响应结果 响应内容
code 状态码
errmsg 错误信息

2.4 接口view定义

  • 接收参数,解析参数
    • json参数,在request.body中,需要进行编码decode()
  • 校验参数
  • 读取用户信息,如果未登录,直接返回,不用保存
  • 连接redis数据库
  • 去重
  • 插入
  • 截取
  • 返回前端响应结果
# apps/users/views.py 
class UserBrowseHistory(LoginRequiredJSONMixin, View):
    """用户浏览记录"""

    def post(self, request):
        """保存用户浏览记录"""
        json_str=request.body.decode()
        json_dict=json.loads(json_str)
        sku_id = json_dict.get('sku_id')

        try:
            sku=SKU.Objects.get(id=sku_id)
        except Exception as e:
            return http.HttpResponseForbidden('sku_id不存在')

        # 获取用信息
        user = request.user

        # 连接数据库redis 3
        redis_conn = get_redis_connection('history')
        redis_conn.lrem('history_%s' % user.id, 0, sku_id)                        # 去重
        redis_conn.lpush('history_%s' % user.id, sku_id)                          # 插入
        redis_conn.ltrim('history_%s' % user.id, 0, USER_HISTORY_COUNT_LIMIT)     # 截取

        # 响应结果
        return http.JsonResponse({
    
    'code': RETCODE.OK, 'errmsg': 'OK'})

2.5 路由定义

在这里插入图片描述

2.6 代码优化

  • 连续访问可有管道
    在这里插入图片描述

2.7 运行结果查看

在这里插入图片描述

3、 查询用户浏览记录

  • 在用户信息表页面中,展示用户浏览记录

3.1 请求方式

选项 方案
请求方法 POST
请求地址 /users/browse_histories/

3.2 请求参数 : 无

3.3 响应结果 : JSON

响应结果 响应内容
errmsg 错误信息
skus[ ] 商品SKU列表数据
id 商品SKU编号
name 商品SKU名称
default_image_url 商品SKU默认图片
price 商品SKU单价

3.4 接口view定义

  • 连接redis数据库
  • 获取用户信息
  • 查询用户浏览记录
  • 生成用户浏览记录字典
  • 返回前端响应结果
    def get(self,request):
        """查询用户商品浏览器记录"""

        redis_conn = get_redis_connection('history')
        user = request.user
        sku_ids = redis_conn.lrange('history_%s' % user.id, 0, -1)
        # print(sku_ids)

        skus = []
        for sku_id in sku_ids:
            sku = SKU.objects.get(id=sku_id)
            skus.append({
    
    
                'id': sku.id,
                'name': sku.name,
                'price': sku.price,
                'default_image_url': sku.default_image.url,

            })

        return http.JsonResponse({
    
    'code': RETCODE.OK, 'errmsg': 'OK', 'skus': skus})

3.4 路由已经定义过了

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/laoluobo76/article/details/115279822
今日推荐