【Django开发】前后端分离django美多商城项目第16篇:商品详情页,1. 统计分类商品访问量模型类【附代码文档】

举报
程序员一诺python 发表于 2025/04/06 16:30:56 2025/04/06
【摘要】 本教程的知识点为:欢迎来到美多商城! 项目准备 项目介绍 项目需求分析 1. 项目主要页面介绍 展示用户注册页面 创建用户模块子应用 1. 创建用户模块子应用 2. 查看项目导包路径 3. 注册用户模块子应用 用户注册业务实现 用户注册前端逻辑 1. 用户注册页面绑定Vue数据 2. 用户注册JS文件实现用户交互 4. 知识要点 图形验证码 图形验证码接口设计和定义 1. 图形

本教程的知识点为: 项目准备 项目准备 配置 1. 修改settings/dev.py 文件中的路径信息 2. INSTALLED_APPS 3. 数据库 用户部分 图片 1. 后端接口设计: 视图原型 2. 具体视图实现 用户部分 使用Celery完成发送 判断帐号是否存在 1. 判断用户名是否存在 后端接口设计: 用户部分 JWT 什么是JWT 起源 传统的session认证 用户部分 登录 1. 业务说明 2. 后端接口设计 3. 后端实现 登录 使用登录的流程 创建模型类 urllib使用说明 登录回调处理 登录 使用登录的流程 创建模型类 urllib使用说明 绑定用户身份接口 邮件与验证 学习目标: 业务说明: 技术说明: 保存邮箱并发送验证邮件 省市区地址查询 数据库建表 说明 页面静态化 注意 定时任务 安装 部分 详情页 异步任务的触发 。 后端接口设计 收货地址 使用缓存 安装 使用方法 为省市区视图添加缓存 数据库表设计 表结构 数据表结构 首页数据表结构 Docker使用 Docker简介 用户浏览历史记录 1. 保存 后端接口设计 后端实现 搜索 1. 需求分析 2. 搜索引擎原理 3. Elasticsearch 部分 业务需求分析 技术实现 数据存储设计 1. Redis保存已登录用户 商品部分 业务需求分析 技术实现 查询数据 1. 后端接口设计 部分 业务需求分析 技术实现 登录合并 修改登录视图 部分 保存 1. 后端接口设计 2. 后端实现 保存的思路 创建数据库模型类 接入 开发平台登录 沙箱环境 Xadmin 1. 安装 2. 使用 站点的全局配置 站点Model管理。 在Ubuntu中安装 2. 启动与停止 3. 镜像操作 端与自定义文件存储系统 1. 的Python客户端 安装 使用。

完整笔记资料代码:https://gitee.com/yinuo112/Backend/tree/master/Django/前后端分离django美多商城项目/note.md

感兴趣的小伙伴可以自取哦~


全套教程部分目录:


部分文件图片:

商品详情页

统计分类商品访问量

提示:

  • 统计分类商品访问量 是统计一天内该类别的商品被访问的次数。
  • 需要统计的数据,包括商品分类,访问次数,访问时间。
  • 一天内,一种类别,统计一条记录。

1. 统计分类商品访问量模型类

模型类定义在goods.models.py中,然后完成迁移建表。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
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. 统计分类商品访问量后端逻辑

1.请求方式

选项 方案
请求方法 POST
请求地址 /detail/visit/(?P\d+)/
>
2.请求参数:路径参数
参数名 类型 是否必传 说明
category_id string 商品分类ID,第三级分类
>
3.响应结果:JSON
字段 说明
code 状态码
errmsg 错误信息
>
4.后端接口定义和实现
  • 如果访问记录存在,说明今天不是第一次访问,不新建记录,访问量直接累加。
  • 如果访问记录不存在,说明今天是第一次访问,新建记录并保存访问量。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class DetailVisitView(View):
    """详情页分类商品访问量"""

    def post(self, request, category_id):
        """记录分类商品访问量"""
        try:
            category = models.GoodsCategory.objects.get(id=category_id)
        except models.GoodsCategory.DoesNotExist:
            return http.HttpResponseForbidden('缺少必传参数')

        # 获取今天的日期
        t = timezone.localtime()
        today_str = '%d-%02d-%02d' % (t.year, t.month, t.day)
        today_date = datetime.datetime.strptime(today_str, '%Y-%m-%d')
        try:
            # 查询今天该类别的商品的访问量
            counts_data = category.goodsvisitcount_set.get(date=today_date)
        except models.GoodsVisitCount.DoesNotExist:
            # 如果该类别的商品在今天没有过访问记录,就新建一个访问记录
            counts_data = models.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'})

用户浏览记录

设计浏览记录存储方案

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

1. 存储数据说明

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

2. 存储位置说明

  • 用户浏览记录是临时数据,且经常变化,数据量不大,所以我们选择内存型数据库进行存储。
  • 存储位置:Redis数据库 3号库
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
CACHES = {
    "history": { # 用户浏览记录
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/3",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    },
}

3. 存储类型说明

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

4. 存储逻辑说明

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

保存和查询浏览记录

1. 保存用户浏览记录

1.请求方式

选项 方案
请求方法 POST
请求地址 /browse_histories/
>
2.请求参数:JSON
参数名 类型 是否必传 说明
sku_id string 商品SKU编号
>
3.响应结果:JSON
字段 说明
code 状态码
errmsg 错误信息
>
4.后端接口定义和实现
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class UserBrowseHistory(LoginRequiredJSONMixin, View):
    """用户浏览记录"""

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

        # 校验参数
        try:
            models.SKU.objects.get(id=sku_id)
        except models.SKU.DoesNotExist:
            return http.HttpResponseForbidden('sku不存在')

        # 保存用户浏览数据
        redis_conn = get_redis_connection('history')
        pl = redis_conn.pipeline()
        user_id = request.user.id

        # 先去重
        pl.lrem('history_%s' % user_id, 0, sku_id)
        # 再存储
        pl.lpush('history_%s' % user_id, sku_id)
        # 最后截取
        pl.ltrim('history_%s' % user_id, 0, 4)
        # 执行管道
        pl.execute()

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

2. 查询用户浏览记录

1.请求方式

选项 方案
请求方法 GET
请求地址 /browse_histories/
>
2.请求参数:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10

3.响应结果:JSON

字段 说明
code 状态码
errmsg 错误信息
skus[ ] 商品SKU列表数据
id 商品SKU编号
name 商品SKU名称
default_image_url 商品SKU默认图片
price 商品SKU单价
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
    "code":"0",
    "errmsg":"OK",
    "skus":[
        {
            "id":6,
            "name":"Apple iPhone 8 Plus (A1864) 256GB 深空灰色 移动联通电信4G手机",
            "default_image_url":"
            "price":"7988.00"
        },
        ......
    ]
}

4.后端接口定义和实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class UserBrowseHistory(LoginRequiredJSONMixin, View):
    """用户浏览记录"""

    def get(self, request):
        """获取用户浏览记录"""
        # 获取Redis存储的sku_id列表信息
        redis_conn = get_redis_connection('history')
        sku_ids = redis_conn.lrange('history_%s' % request.user.id, 0, -1)

        # 根据sku_ids列表数据,查询出商品sku信息
        skus = []
        for sku_id in sku_ids:
            sku = models.SKU.objects.get(id=sku_id)
            skus.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price
            })

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

Vue渲染用户浏览记录

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<div class="has_view_list" v-cloak>
    <ul class="goods_type_list clearfix">
        <li v-for="sku in histories">
            <a :href="sku.url"><img :src="sku.default_image_url"></a>
            <h4><a :href="sku.url">[[ sku.name ]]</a></h4>
            <div class="operate">
                <span class="price">[[ sku.price ]]</span>
                <span class="unit"></span>
                <a href="javascript:;" class="add_goods" title="加入购物车"></a>
            </div>
        </li>
    </ul>
</div>

购物车

购物车存储方案


  • 用户登录与未登录状态下,都可以保存购物车数据。
  • 用户对购物车数据的操作包括:全选等等
  • 每个用户的购物车数据都要做唯一性的标识。

1. 登录用户购物车存储方案

1.存储数据说明

  • 如何描述一条完整的购物车记录?

  • 用户itcast,选择了两个 iPhone8 添加到了购物车中,状态为勾选

  • 一条完整的购物车记录包括:用户商品数量勾选状态

  • 存储数据:user_idsku_idcountselected

    2.存储位置说明

  • 购物车数据量小,结构简单,更新频繁,所以我们选择内存型数据库Redis进行存储。

  • 存储位置:Redis数据库 4号库
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
"carts": {
    "BACKEND": "django_redis.cache.RedisCache",
    "LOCATION": "redis://127.0.0.1:6379/4",
    "OPTIONS": {
        "CLIENT_CLASS": "django_redis.client.DefaultClient",
    }
},

3.存储类型说明

  • 提示:我们很难将用户、商品、数量、勾选状态存放到一条Redis记录中。所以我们要把购物车数据合理的分开存储。
  • 用户、商品、数量:hash
  • carts_user_id: {sku_id1: count, sku_id3: count, sku_id5: count, ...}

  • 勾选状态:set

  • 只将已勾选商品的sku_id存储到set中,比如,1号和3号商品是被勾选的。
  • selected_user_id: [sku_id1, sku_id3, ...]

4.存储逻辑说明

  • 当要添加到购物车的商品已存在时,对商品数量进行累加计算。
  • 当要添加到购物车的商品不存在时,向hash中新增field和value即可。

2. 未登录用户购物车存储方案

1.存储数据说明

  • 存储数据:user_idsku_idcountselected

    2.存储位置说明

  • 由于用户未登录,服务端无法拿到用户的ID,所以服务端在生成购物车记录时很难唯一标识该记录。

  • 我们可以将未登录用户的购物车数据缓存到用户浏览器的cookie中,每个用户自己浏览器的cookie中存储属于自己的购物车数据。
  • 存储位置:用户浏览器的cookie

    3.存储类型说明

  • 提示:浏览器的cookie中存储的数据类型是字符串。

  • 思考:如何在字符串中描述一条购物车记录?
  • 结论:JSON字符串可以描述复杂结构的字符串数据,可以保证一条购物车记录不用分开存储。 ```json { "sku_id1":{ "count":"1", "selected":"True" },
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。