十日Python项目——第七日(商品购物车)

news2024/12/22 22:36:49

#前言:

在最近十天我会用Python做一个购物类电商项目,会用到Django+Mysql+Redis+Vue等。

今天是第六天,主要负责撰写编写关于商品购物车的编写,以及相应的增删改查。若是有不懂大家可以先阅读我的前六篇博客以能够顺承。

若是大家基础有不懂的,小编前面已经关于Django博客都更新完了,大家可以自行查看。若是有需要更改的地方欢迎大家指正,同时也欢迎大家关注点赞收藏等待后续,小编会尽力更新优质博客。

在此我会直接继承上一篇博客继续往下写。

十四、购物车:

关于设计购物车的思路很简单,首先就是能获取到我们商品的数据(主要以id为媒介)将其能够相应到前端页面吗,其次关于其它操作我在下面会详细撰写。

1、响应添加购物车数据:

创建应用实现购物车的功能操作 —— carts

配置 redis 数据库缓存购物车中的商品数据:

# 缓存 购物车商品数据
    "carts" : {
        "BACKEND" : "django_redis.cache.RedisCache",
        "LOCATION" : "redis://127.0.0.1:6379/3",
        "OPTIONS" : {
            "CLIENT_CLASS" : "django_redis.client.DefaultClient"
        }
    },

关于相应页面和购物车添加:

# 购物车页面
path('carts/' , views.CartsView.as_view() , name='carts'),

class CartsView(View):
    '''
    响应购物车页面
    '''
    def get(self , request):
        # 响应页面
        return render(request , 'cart.html')
    def post(self , request):
        # 购物车商品添加 {sku_id: 3, count: 1}
        sku_dict = json.loads(request.body.decode())
        sku_id = sku_dict.get("sku_id")
        count = sku_dict.get("count")
        selected = sku_dict.get("selected" , True)

        try:
            SKU.objects.get(id=sku_id)
        except Exception:
            return HttpResponseForbidden('商品不存在')

        user = request.user
        redis_conn = get_redis_connection("carts")
        # user_id = {sku_id:count , sku_id2:count}
        redis_conn.hincrby('cart_%s'%user.id , sku_id , count)
        if selected:
            # 结果为 True 保存勾选状态
            redis_conn.sadd('selected_%s'%user.id , sku_id)
        return JsonResponse({'code':RETCODE.OK , 'errmsg':'OK'})

思路也很简单,这个post请求主要是负责将我们post请求到的数据(也就是我们需要添加的商品)获取到,注意因为是json数据类型,所有需要解码。其次将获取到的数据按照商品唯一的商品id将其存储到reedis数据库,其中注意有一个关于是否勾选的选项:

同样的如果你选择勾选的话就要将其保存到redis数据库中。

2、渲染购物车页面:

渲染前端页面的思路:就是将我们需要响应到前端的商品数据按照get请求获取到,将他们存储到一个字典当中,然后将数据一个个的按照商品id将要相应的数据存储到元组当中,最后响应传递给前端页面。

class CartsView(View):
    '''
    响应购物车页面
    '''
    def get(self , request):
        # 响应页面
        user = request.user
        redis_conn = get_redis_connection("carts")
        redis_cart = redis_conn.hgetall('cart_%s'%user.id)
        redis_selected = redis_conn.smembers('selected_%s'%user.id)
        # cart_dict =  {sku1:{count:150 , selected:true} , sku2:{},……}
        cart_dict = {}
        for sku_id , count in redis_cart.items():
            cart_dict[int(sku_id)] = {
                'count' : int(count),
                'selected' : sku_id in redis_selected
            }

        # 获取购物车中的所有商品数据
        sku_ids = cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        cart_skus = []
        for sku in skus:
            cart_sku_dict = {
                "id" : sku.id,
                "name" : sku.name,
                'price' : str(sku.price),
                'count' : cart_dict.get(sku.id).get('count'),
                'selected' : str(cart_dict.get(sku.id).get("selected")),
                'amount' : str(sku.price * cart_dict.get(sku.id).get('count')),
                'default_image_url': STATIC_URL+'images/goods'+sku.default_image.url+'.jpg'
            }
            cart_skus.append(cart_sku_dict)
        context = {'cart_skus':cart_skus}
        return render(request , 'cart.html' , context=context)

修改 cart.html 对应标签的内容

<ul class="cart_list_td clearfix" v-for="(cart_sku , index) in carts" v-cloak>
    <li class="col01"><input type="checkbox" name="" v-model="cart_sku.selected" @checked="update_selected(index)"></li>
    <li class="col02"><img :src="cart_sku.default_image_url"></li>
    <li class="col03">[[ cart_sku.name ]]</li>
    <li class="col04">台</li>
    <li class="col05">[[ cart_sku.price ]]元</li>
    <li class="col06">
        <div class="num_add">
            <a @click="on_add(index)" class="add fl">+</a>
            <input type="text" class="num_show fl" v-model="cart_sku.count" @blur="on_input(index)">
            <a @click="on_minus(index)" class="minus fl">-</a>
        </div>
    </li>
    <li class="col07">[[ cart_sku.amount ]]元</li>
    <li class="col08"><a @click="on_delete(index)">删除</a></li>
</ul>
<ul class="settlements">
    <li class="col01"><input type="checkbox" name="" @change="on_selected_all" v-model="selected_all"></li>
    <li class="col02">全选</li>
    <li class="col03">合计(不含运费):<span>¥</span><em>[[ total_selected_amount ]]</em><br>共计<b>[[ total_selected_count ]]</b>件商品</li>
    <li class="col04"><a href="place_order.html">去结算</a></li>
</ul>
<script type="text/javascript">
    let carts = {{ cart_skus|safe }};
</script>

3、修改购物车购买数量:

修改 购买数量的思路和前面一样,我们要做的就是和前面添加购物车的思路唯一思路上不一样的就是响应出来的价钱要的是数量乘以原先的价格,其次还有一点要注意的是我们要的是勾选了select的数据。

注意,它的请求方式为put请求:

def put(self , request):
        # {sku_id: 6, count: 3, selected: true}
        sku_dict = json.loads(request.body.decode())
        sku_id = sku_dict.get("sku_id")
        count = sku_dict.get("count")
        selected = sku_dict.get("selected" , True)

        try:
            sku = SKU.objects.get(id=sku_id)
        except Exception:
            return  HttpResponseForbidden('商品不存在')

        user = request.user
        redis_conn = get_redis_connection("carts")
        redis_conn.hincrby('cart_%s'%user.id , sku_id , count)
        if selected:
            redis_conn.sadd('selected_%s'%user.id , sku_id)
        else:
            redis_conn.srem('selected_%s' % user.id, sku_id)
        cart_sku_dict = {
            "id": sku.id,
            "name": sku.name,
            'price': sku.price,
            'count': count,
            'selected': selected,
            'amount': sku.price * count ,
            'default_image_url': STATIC_URL + 'images/goods/' + sku.default_image.url + '.jpg'
        }
        return JsonResponse({'code':RETCODE.OK , 'errmsg':'OK', 'cart_sku':cart_sku_dict})

4、删除购物车商品数据:

删除购物车商品数据的思路也很简单,主要是获取到delete请求获取到的需要删除的数据后我们将其按照id将数据从redis数据库删除。

def delete(self , request):
        # 删除购物车数据
        sku_dict = json.loads(request.body.decode())
        sku_id = sku_dict.get('sku_id')

        user = request.user
        redis_conn = get_redis_connection("carts")
        redis_conn.hdel('cart_%s' % user.id, sku_id)
        redis_conn.srem('selected_%s' % user.id, sku_id)
        return JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})

5、全选购物车商品数据:

全选购物车商品的最主要思路就是来一个循环将其选择状态都保存到redis数据库。

# 全选购物车
path('carts/selection/' , views.CratSelectAllView.as_view()),

class CratSelectAllView(View):
    '''
    全选购物车商品
    '''
    def put(self , request):
        selected_dict = json.loads(request.body.decode())
        selected = selected_dict.get('selected')

        user = request.user
        redis_conn = get_redis_connection("carts")
        redis_cart = redis_conn.hgetall('cart_%s' % user.id)
        sku_ids = redis_cart.keys()
        if selected:
            redis_conn.sadd('selected_%s' % user.id, *sku_ids)
        else:
            for sku_id in sku_ids:
                redis_conn.srem('selected_%s' % user.id, sku_id)
        return JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})

6、浏览记录:

同样的将浏览记录存储在redis数据库当中:

# 缓存 浏览记录
    "history" : {
        "BACKEND" : "django_redis.cache.RedisCache",
        "LOCATION" : "redis://127.0.0.1:6379/4",
        "OPTIONS" : {
            "CLIENT_CLASS" : "django_redis.client.DefaultClient"
        }
    },

在用户的应用下实现视图操作:

浏览记录的应用主要思路是:先将我们浏览的数据get请求到它的信息,然后将其存入redis数据库,然后按照post请求将它负责去重-保存-截取的思路(因为在一定时间内连续访问同一商品我们之存入最近访问的一次)。

# 用户的浏览记录
path('browse_histories/' , views.UserBrowerHistoryView.as_view()),

class UserBrowerHistoryView(View):
    '''
    浏览记录
    '''
    def get(self , request):
        redis_conn = get_redis_connection('history')
        user = request.user
        sku_ids = redis_conn.lrange("history_%s"%user.id , 0 , -1)

        skus = []
        for sku_id in sku_ids:
            sku = SKU.objects.get(id = sku_id)
            sku_dict = {
                'id': sku.id,
                'name' : sku.name,
                'price' : sku.price,
                'default_image_url' : STATIC_URL + 'images/goods/' + sku.default_image.url + '.jpg'
            }
            skus.append(sku_dict)
        return JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK' , 'skus':skus})

    def post(self , request):
        sku_dict = json.loads(request.body.decode())
        sku_id = sku_dict.get('sku_id')

        try:
            SKU.objects.get(id=sku_id)
        except Exception:
            return HttpResponseForbidden('商品不存在')

        redis_conn = get_redis_connection('history')
        user = request.user
        # 去重
        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 , 20)

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

#总结:

关于购物车的实现我们最主要的思路还是按照将其从页面请求到需要操作的数据,然后后端请求后响应回前端页面,而数据的存储我们存储到redis数据库当中,因为购物车是在可以不断刷新的,用redis的效率更高一点。

最后,若是大家发现小编的博客需要更改的地方欢迎各位评论指正,同时欢迎大家点赞关注小编,您的支持将是小编变强的最大动力!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2036689.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Github Copilot 使用技巧

&#x1f3af;目标读者 本文不包含如何安装 Github Copilot本文介绍了 Github Copilot 使用方法和一些技巧 本人已经使用 Github Copilot 2 年了&#xff0c;交了 3 次年费&#xff0c;每年 100$ 着实心痛&#xff0c;但是用着确实爽歪歪 但是感觉一直只用了一小部分功能&am…

(第二十七天)

上午 核心&#xff1a;内核中的 ipvs &#xff0c; ipvsadm 1 、安装 ipvsadm [rootnat ~] # yum -y install ipvsadm 2 、配置规则 查看所有的规则&#xff0c;如果已经配置好规则&#xff0c;重启之后也就没有了 [rootnat ~] # ipvsadm -L -n 1 、配置 vip 网卡 &…

服装租赁押金管理-押金原路退回系统开通方法

一、婚纱影楼服装租赁收押金必要性 1. 保障服装的按时归还&#xff1a; - 押金的存在能促使租客按时归还服装&#xff0c;避免因拖延归还影响后续的租赁业务。比如&#xff0c;在一些大型活动期间&#xff0c;服装租赁需求旺盛&#xff0c;如果租客不按时归还&#xff0c;…

HTML样式- CSS——WEB开发系列08

一、HTML 基础概述 HTML 用于创建网页的结构。网页的所有内容&#xff0c;例如文本、图像、链接、表单等&#xff0c;都是通过 HTML 标签来定义的。以下是一个简单的 HTML 文档结构示例&#xff1a; <!DOCTYPE html> <html lang"en"> <head><…

matlab 音频音量处理(音量大小按照dB调节)

1 音量(声压级)以分贝(dB)表示的计算公式为: 2 % 已知的 x 值 x = 0:-1:-127; % 在这里填入 x 的具体值% 计算 y %y = 10

浅谈php://filter的妙用

文章目录 分析源码巧用编码与解码利用字符串操作方法 分析源码 <?php $content <?php exit; ?>; $content . $_POST[txt]; file_put_contents($_POST[filename], $content);首先&#xff0c;先分析一下这段代码。 首先他定义了content为’<?php exit;?>‘…

计算机网络17——IM聊天系统——客户端核心处理类框架搭建

目的 拆开客户端和服务端&#xff0c;使用Qt实现客户端&#xff0c;VS实现服务端 Qt创建项目 Qt文件类型 .pro文件&#xff1a;配置文件&#xff0c;决定了哪些文件参与编译&#xff0c;怎样参与编译 .h .cpp .ui&#xff1a;画图文件 Qt编码方式 Qt使用utf-8作为编码方…

服务器被ddos攻击多久能恢复?具体怎么操作

服务器被ddos攻击多久能恢复&#xff1f;如果防御措施得当&#xff0c;可能几分钟至几小时内就能缓解&#xff1b;若未采取预防措施或攻击特别猛烈&#xff0c;则可能需要几小时甚至几天才能完全恢复。服务器被DDoS攻击的恢复时间取决于攻击的规模和强度、服务器的配置和性能以…

【C++】类与对象(中)_7.const成员函数

7.const成员 7.1 const修饰类的成员函数 将const修饰的类成员函数称之为const成员函数&#xff0c;const修饰类成员函数&#xff0c;实际修饰该成员函数隐含的this指针&#xff0c;表明在该成员函数中不能对类的任何成员进行修改。 我们来看看下面的代码 #define _CRT_SECU…

【ARM CoreLink 系列 5.1 -- CI-700 各种 Node 组件详细介绍】

请阅读【ARM CoreLink 文章专栏导读】 文章目录 CI-700 组件(Components)RN-I( I/O-coherent Request Node) 和 RN-D(I/O coherent Request Node with DVM)HN-F(Fully coherent Home Node)IO coherent Home Node (HN-I)IO coherent Home Node with Debug Trace Controller (H…

JSON与Jsoncpp库:数据交换的灵活选择

目录 引言 一.JSON简介 二. Jsoncpp库概述 三. Jsoncpp核心类介绍 3.1 Json::Value类 3.2 序列化与反序列化类 四. 实现序列化 五. 实现反序列化 结语 引言 在现代软件开发中&#xff0c;数据交换格式扮演着至关重要的角色。JSON&#xff08;JavaScript Object Notati…

鸿蒙(API 12 Beta3版)【媒体会话提供方】本地媒体会话

音视频应用在实现音视频功能的同时&#xff0c;需要作为媒体会话提供方接入媒体会话&#xff0c;在媒体会话控制方&#xff08;例如播控中心&#xff09;中展示媒体相关信息&#xff0c;及响应媒体会话控制方下发的播控命令。 基本概念 媒体会话元数据&#xff08;AVMetadata…

WordPress原创插件:Download-block-plugin下载按钮图标美化

WordPress原创插件&#xff1a;Download-block-plugin下载按钮图标美化 https://download.csdn.net/download/huayula/89632743

Mapreduce_csv_averageCSV文件计算平均值

csv文件求某个平均数据 查询每个部门的平均工资&#xff0c;最后输出 数据处理过程 employee_noheader.csv&#xff08;没做关于首行的处理&#xff0c;运行时请自行删除&#xff09; EmployeeID,EmployeeName,DepartmentID,Salary 1,ZhangSan,101,5000 2,LiSi,102,6000…

疫情下图书馆管理系统

TOC springboot126疫情下图书馆管理系统 系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管…

mock.js的简单使用~

1、什么是mock? mock.js:是一款模拟数据生成器&#xff0c;可以生成随机数据&#xff0c;拦截 Ajax 请求. 2、mock的作用。 可以通过mock来模拟后端接口&#xff0c;可随机生成所需数据&#xff0c;模拟对数据的增删改查。并且截Ajax请求不需要修改既有代码就可以拦截&…

RCE-eval长度限制突破技巧

目录 一、长度17的限制绕过 1、最简单的绕过 &#xff08;一&#xff09;绕过 &#xff08;二&#xff09;编写一句话木马 2、文件包含的利用 &#xff08;一&#xff09;远程文件包含的利用 &#xff08;二&#xff09;本地文件包含的利用 3、usort绕过 &#xff08…

BGP路由优选(五)

当到达同一个目的网段存在多条路由时&#xff0c;BGP通过如下的次序进行路由优选&#xff1a; 丢弃下一跳不可达的路由。 优选Preferred-Value属性值最大的路由。优选Local_Preference属性值最大的路由。本地始发的BGP路由优于从其他对等体学习到的路由&#xff0c;本地始发的路…

使用腾讯云存储桶COS来实现上传和下载图片功能

有个需求&#xff0c;需要上传和下载图片&#xff0c;我决定使用腾讯云存储桶来做服务器存储目录&#xff0c;供程序上传和下载使用。 1、首先打开对应网站&#xff1a;云产品免费体验馆_云产品免费试用_个人云产品试用-腾讯云&#xff0c;点击左边的"存储"项&#x…

proxy负载均衡

endpoint &#xff1a; 终点、终端 看service服务器的ip kubectl get ep backend -> real server &#xff1a;真正提供web服务的服务器 负载均衡器 load balancer --》LB USER -->LB --->BACKEND(real server) nginx SERVICE --->很多的endpoint--》po…