商品详情页detail.html添加加入购物车按钮

<a href="javascript:;" sku_id="{{ sku.id }}" class="add_cart" id="add_cart">加入购物车</a>
....
<script>
$('#add_cart').click(function(){
// 获取商品id和商品数量
sku_id = $(this).attr('sku_id') // attr prop
count = $('.num_show').val()
csrf = $('input[name="csrfmiddlewaretoken"]').val()
// 组织参数
params = {'sku_id':sku_id, 'count':count, 'csrfmiddlewaretoken':csrf}
// 发起ajax post请求,访问/cart/add, 传递参数:sku_id count
$.post('/cart/add', params, function (data) {
if (data.res == 5){
// 添加成功
$(".add_jump").css({'left':$add_y+80,'top':$add_x+10,'display':'block'})
$(".add_jump").stop().animate({
'left': $to_y+7,
'top': $to_x+7},
"fast", function() {
$(".add_jump").fadeOut('fast',function(){
// 重新设置用户购物车中商品的条目数
$('#show_count').html(data.total_count);
});
});
}
else{
// 添加失败
alert(data.errmsg)
}
})
})
</script>

视图函数views.py中添加add功能

from django.shortcuts import render
from django.views.generic import View
from django.http import JsonResponse from goods.models import GoodsSKU
from django_redis import get_redis_connection # Create your views here.
# 添加商品到购物车:
# 1)请求方式,采用ajax post
# 如果涉及到数据的修改(新增,更新,删除), 采用post
# 如果只涉及到数据的获取,采用get
# 2) 传递参数: 商品id(sku_id) 商品数量(count) # ajax发起的请求都在后台,在浏览器中看不到效果
# /cart/add
class CartAddView(View):
'''购物车记录添加'''
def post(self, request):
'''购物车记录添加'''
user = request.user
if not user.is_authenticated():
# 用户未登录
return JsonResponse({'res':0, 'errmsg':'请先登录'}) # 接收数据
sku_id = request.POST.get('sku_id')
count = request.POST.get('count') # 数据校验
if not all([sku_id, count]):
return JsonResponse({'res':1, 'errmsg':'数据不完整'}) # 校验添加的商品数量
try:
count = int(count)
except Exception as e:
# 数目出错
return JsonResponse({'res':2, 'errmsg':'商品数目出错'}) # 校验商品是否存在
try:
sku = GoodsSKU.objects.get(id=sku_id)
except GoodsSKU.DoesNotExist:
# 商品不存在
return JsonResponse({'res':3, 'errmsg':'商品不存在'}) # 业务处理:添加购物车记录
conn = get_redis_connection('default')
cart_key = 'cart_%d'%user.id
# 先尝试获取sku_id的值 -> hget cart_key 属性
# 如果sku_id在hash中不存在,hget返回None
cart_count = conn.hget(cart_key, sku_id)
if cart_count:
# 累加购物车中商品的数目
count += int(cart_count) # 校验商品的库存
if count > sku.stock:
return JsonResponse({'res':4, 'errmsg':'商品库存不足'}) # 设置hash中sku_id对应的值
# hset->如果sku_id已经存在,更新数据, 如果sku_id不存在,添加数据
conn.hset(cart_key, sku_id, count) # 计算用户购物车商品的条目数
total_count = conn.hlen(cart_key) # 返回应答
return JsonResponse({'res':5, 'total_count':total_count, 'message':'添加成功'})

购物车页面

跳转到购物车

base.html中

 <a href="{% url 'cart:show' %}" class="cart_name fl">我的购物车</a>

视图函数views.py添加CartInfoView视图功能

# /cart/
from utils.mixin import LoginRequiredMinxin # 登录校验
class CartInfoView(LoginRequiredMinxin, View):
'''购物车页面显示'''
def get(self, request):
'''显示'''
# 获取登录的用户
user = request.user
# 获取用户购物车中商品的信息
conn = get_redis_connection('default')
cart_key = 'cart_%d'%user.id
# {'商品id':商品数量, ...}
cart_dict = conn.hgetall(cart_key) skus = []
# 保存用户购物车中商品的总数目和总价格
total_count = 0
total_price = 0
# 遍历获取商品的信息
for sku_id, count in cart_dict.items():
# 根据商品的id获取商品的信息
sku = GoodsSKU.objects.get(id=sku_id)
# 计算商品的小计
amount = sku.price*int(count)
# 动态给sku对象增加一个属性amount, 保存商品的小计
sku.amount = amount
# 动态给sku对象增加一个属性count, 保存购物车中对应商品的数量
sku.count = count
# 添加
skus.append(sku) # 累加计算商品的总数目和总价格
total_count += int(count)
total_price += amount # 组织上下文
context = {'total_count':total_count,
'total_price':total_price,
'skus':skus} # 使用模板
return render(request, 'cart.html', context)

模板cart.html

{% extends 'layout/base_no_cart.html' %}
{% load staticfiles %}
{% block title %}天天生鲜-购物车{% endblock title %}
{% block page_title %}购物车{% endblock page_title %}
{% block body %}
<div class="total_count">全部商品<em>{{ total_count }}</em>件</div>
<ul class="cart_list_th clearfix">
<li class="col01">商品名称</li>
<li class="col02">商品单位</li>
<li class="col03">商品价格</li>
<li class="col04">数量</li>
<li class="col05">小计</li>
<li class="col06">操作</li>
</ul>
<form method="post" action="">
{% for sku in skus %}
<ul class="cart_list_td clearfix">
<li class="col01"><input type="checkbox" name="sku_ids" value="{{ sku.id }}" checked></li>
<li class="col02"><img src="{{ sku.image.url }}"></li>
<li class="col03">{{ sku.name }}<br><em>{{ sku.price }}元/{{ sku.unite }}</em></li>
<li class="col04">{{ sku.unite }}</li>
<li class="col05">{{ sku.price }}元</li>
<li class="col06">
<div class="num_add">
<a href="javascript:;" class="add fl">+</a>
<input type="text" sku_id="{{ sku.id }}" class="num_show fl" value="{{ sku.count }}">
<a href="javascript:;" class="minus fl">-</a>
</div>
</li>
<li class="col07">{{ sku.amount }}元</li>
<li class="col08"><a href="javascript:;">删除</a></li>
</ul>
{% endfor %} <ul class="settlements">
{% csrf_token %}
<li class="col01"><input type="checkbox" name="" checked=""></li>
<li class="col02">全选</li>
<li class="col03">合计(不含运费):<span>¥</span><em>{{ total_price }}</em><br>共计<b>{{ total_count }}</b>件商品</li>
<li class="col04"><input type="submit" value="去结算"></li>
</ul>
</form>
{% endblock body %} {% block bottomfiles %}
<script src="{% static 'js/jquery-1.12.4.min.js' %}"></script>
<script>
// 计算被选中的商品的总件数和总价格
function update_page_info() {
// 获取所有被选中的商品的checkbox
// 获取所有被选中的商品所在的ul元素
total_count = 0
total_price = 0
$('.cart_list_td').find(':checked').parents('ul').each(function () {
// 获取商品的数目和小计
count = $(this).find('.num_show').val()
amount = $(this).children('.col07').text()
// 累加计算商品的总件数和总价格
count = parseInt(count)
amount = parseFloat(amount)
total_count += count
total_price += amount
})
// 设置被选中的商品的总件数和总价格
$('.settlements').find('em').text(total_price.toFixed(2))
$('.settlements').find('b').text(total_count)
} // 计算商品的小计
function update_goods_amount(sku_ul) {
// 获取商品的价格和数量
count = sku_ul.find('.num_show').val()
price = sku_ul.children('.col05').text()
// 计算商品的小计
amount = parseInt(count)*parseFloat(price)
// 设置商品的小计
sku_ul.children('.col07').text(amount.toFixed(2)+'元')
} // 商品的全选和全不选
$('.settlements').find(':checkbox').change(function () {
// 获取全选的checkbox的选中状态
is_checked = $(this).prop('checked')
// 遍历商品的对应的checkbox,设置这些checkbox的选中状态和全选的checkbox保持一致
$('.cart_list_td').find(':checkbox').each(function () {
$(this).prop('checked', is_checked)
})
// 更新页面的信息
update_page_info()
}) // 商品对应的checkbox状态发生改变时,设置全选checkbox的状态
$('.cart_list_td').find(':checkbox').change(function () {
// 获取页面上所有商品的数目
all_len = $('.cart_list_td').length
// 获取页面上被选中的商品的数目
checked_len = $('.cart_list_td').find(':checked').length
is_checked = true
if (checked_len < all_len){
is_checked = false
}
$('.settlements').find(':checkbox').prop('checked', is_checked)
// 更新页面的信息
update_page_info()
}) // 更新购物车中商品的数量
error_update = false
total = 0
function update_remote_cart_info(sku_id, count) {
csrf = $('input[name="csrfmiddlewaretoken"]').val()
// 组织参数
params = {'sku_id':sku_id, 'count':count, 'csrfmiddlewaretoken':csrf}
// 设置ajax请求为同步
$.ajaxSettings.async = false
// 发起ajax post请求,访问/cart/update, 传递参数:sku_id count
// 默认发起的ajax请求都是异步的,不会等回调函数执行
$.post('/cart/update', params, function (data) {
if (data.res == 5){
// 更新成功
error_update = false
total = data.total_count
}
else{
// 更新失败
error_update = true
alert(data.errmsg)
}
})
// 设置ajax请求为异步
$.ajaxSettings.async = true
} // 购物车商品数量的增加
$('.add').click(function () {
// 获取商品的id和商品的数量
sku_id = $(this).next().attr('sku_id')
count = $(this).next().val() // 组织参数
count = parseInt(count)+1 // 更新购物车记录
update_remote_cart_info(sku_id, count) // 判断更新是否成功
if (error_update == false){
// 重新设置商品的数目
$(this).next().val(count)
// 计算商品的小计
update_goods_amount($(this).parents('ul'))
// 获取商品对应的checkbox的选中状态,如果被选中,更新页面信息
is_checked = $(this).parents('ul').find(':checkbox').prop('checked')
if (is_checked){
// 更新页面信息
update_page_info()
}
// 更新页面上购物车商品的总件数
$('.total_count').children('em').text(total)
}
}) // 购物车商品数量的减少
$('.minus').click(function () {
// 获取商品的id和商品的数量
sku_id = $(this).prev().attr('sku_id')
count = $(this).prev().val() // 校验参数
count = parseInt(count)-1
if (count <= 0){
return
} // 更新购物车中的记录
update_remote_cart_info(sku_id, count) // 判断更新是否成功
if (error_update == false){
// 重新设置商品的数目
$(this).prev().val(count)
// 计算商品的小计
update_goods_amount($(this).parents('ul'))
// 获取商品对应的checkbox的选中状态,如果被选中,更新页面信息
is_checked = $(this).parents('ul').find(':checkbox').prop('checked')
if (is_checked){
// 更新页面信息
update_page_info()
}
// 更新页面上购物车商品的总件数
$('.total_count').children('em').text(total)
}
}) // 记录用户输入之前商品的数量
pre_count = 0
$('.num_show').focus(function () {
pre_count = $(this).val()
}) // 手动输入购物车中的商品数量
$('.num_show').blur(function () {
// 获取商品的id和商品的数量
sku_id = $(this).attr('sku_id')
count = $(this).val() // 校验参数
if (isNaN(count) || count.trim().length==0 || parseInt(count)<=0){
// 设置商品的数目为用户输入之前的数目
$(this).val(pre_count)
return
} // 更新购物车中的记录
count = parseInt(count)
update_remote_cart_info(sku_id, count) // 判断更新是否成功
if (error_update == false){
// 重新设置商品的数目
$(this).val(count)
// 计算商品的小计
update_goods_amount($(this).parents('ul'))
// 获取商品对应的checkbox的选中状态,如果被选中,更新页面信息
is_checked = $(this).parents('ul').find(':checkbox').prop('checked')
if (is_checked){
// 更新页面信息
update_page_info()
}
// 更新页面上购物车商品的总件数
$('.total_count').children('em').text(total)
}
else{
// 设置商品的数目为用户输入之前的数目
$(this).val(pre_count)
}
}) // 删除购物车中的记录
$('.cart_list_td').children('.col08').children('a').click(function () {
// 获取对应商品的id
sku_id = $(this).parents('ul').find('.num_show').attr('sku_id')
csrf = $('input[name="csrfmiddlewaretoken"]').val()
// 组织参数
params = {'sku_id':sku_id, 'csrfmiddlewaretoken':csrf}
// 获取商品所在的ul元素
sku_ul = $(this).parents('ul')
// 发起ajax post请求, 访问/cart/delete, 传递参数:sku_id
$.post('/cart/delete', params, function (data) {
if (data.res == 3){
// 删除成功,异常页面上商品所在的ul元素
sku_ul.remove()
// 获取sku_ul中商品的选中状态
is_checked = sku_ul.find(':checkbox').prop('checked')
if (is_checked){
// 更新页面信息
update_page_info()
}
// 重新设置页面上购物车中商品的总件数
$('.total_count').children('em').text(data.total_count)
}
else{
alert(data.errmsg)
}
})
}) </script>
{% endblock bottomfiles %}

视图函数views.py中添加购物车更新和删除功能

# 更新购物车记录
# 采用ajax post请求
# 前端需要传递的参数:商品id(sku_id) 更新的商品数量(count)
# /cart/update
class CartUpdateView(View):
'''购物车记录更新'''
def post(self, request):
'''购物车记录更新'''
user = request.user
if not user.is_authenticated():
# 用户未登录
return JsonResponse({'res': 0, 'errmsg': '请先登录'}) # 接收数据
sku_id = request.POST.get('sku_id')
count = request.POST.get('count') # 数据校验
if not all([sku_id, count]):
return JsonResponse({'res': 1, 'errmsg': '数据不完整'}) # 校验添加的商品数量
try:
count = int(count)
except Exception as e:
# 数目出错
return JsonResponse({'res': 2, 'errmsg': '商品数目出错'}) # 校验商品是否存在
try:
sku = GoodsSKU.objects.get(id=sku_id)
except GoodsSKU.DoesNotExist:
# 商品不存在
return JsonResponse({'res': 3, 'errmsg': '商品不存在'}) # 业务处理:更新购物车记录
conn = get_redis_connection('default')
cart_key = 'cart_%d'%user.id # 校验商品的库存
if count > sku.stock:
return JsonResponse({'res':4, 'errmsg':'商品库存不足'}) # 更新
conn.hset(cart_key, sku_id, count) # 计算用户购物车中商品的总件数 {'1':5, '2':3}
total_count = 0
vals = conn.hvals(cart_key)
for val in vals:
total_count += int(val) # 返回应答
return JsonResponse({'res':5, 'total_count':total_count, 'message':'更新成功'}) # 删除购物车记录
# 采用ajax post请求
# 前端需要传递的参数:商品的id(sku_id)
# /cart/delete
class CartDeleteView(View):
'''购物车记录删除'''
def post(self, request):
'''购物车记录删除'''
user = request.user
if not user.is_authenticated():
# 用户未登录
return JsonResponse({'res': 0, 'errmsg': '请先登录'}) # 接收参数
sku_id = request.POST.get('sku_id') # 数据的校验
if not sku_id:
return JsonResponse({'res':1, 'errmsg':'无效的商品id'}) # 校验商品是否存在
try:
sku = GoodsSKU.objects.get(id=sku_id)
except GoodsSKU.DoesNotExist:
# 商品不存在
return JsonResponse({'res':2, 'errmsg':'商品不存在'}) # 业务处理:删除购物车记录
conn = get_redis_connection('default')
cart_key = 'cart_%d'%user.id # 删除 hdel
conn.hdel(cart_key, sku_id) # 计算用户购物车中商品的总件数 {'1':5, '2':3}
total_count = 0
vals = conn.hvals(cart_key)
for val in vals:
total_count += int(val) # 返回应答
return JsonResponse({'res':3, 'total_count':total_count, 'message':'删除成功'})

django-购物车添加的更多相关文章

  1. AI学习吧-购物车-添加商品接口

    create接口流程 需求:向购物车添加商品 流程:写shopping_cart路由--->写ShoppingCart视图函数--->使用Authuser校验用户是否登录--->首先 ...

  2. django中添加用户

    在django中添加用户,直接在auth_user表中添加会有问题,因为这里密码是加密的,可以通过manage.py shell加入 创建User: 1 >>> from djang ...

  3. django项目添加路由----返回给客户端内容-----windows中的python

    django项目添加路由 url函数的第一个参数是匹配url路径的正则表达式,第2个参数是路由函数 第一个正则表达式是r'^$',其中r表示正则表达式字符串不对转义符进行转义.“^”表示匹配URL路径 ...

  4. Django 购物车模板

    url from django.contrib import admin from django.urls import path, re_path from django.urls import i ...

  5. django通过添加session来保存公共变量

    有时候我们需要所有页面都使用同一个变量,比如用户登录信息.那不可能render每一个页面时都去传递一个变量,会非常麻烦 而用session可以解决这个问题   web的session可以通过reque ...

  6. django中添加新的filter

    给模板传递了一个字典,却发现无法在模板中直接通过key获得value. 查阅资料后,这个问题可以通过添加自定义的filter来解决. 首先在app目录下创建一个templatetags目录,并在它的下 ...

  7. django admin 添加用户出现外键约束错误

    今天在做mxonline项目时,注册了用户表进admin后,想在后台添加一个用户试试,结果出现了错误,经过一番搜索发现以下两个解决方法,不过我只用了一种 报错信息: IntegrityError: ( ...

  8. 给Django Admin添加验证码和多次登录尝试限制

    Django自带的Admin很好用,但是放到生产环境总还差了点什么= = 看看admin的介绍: Django奉行Python的内置电池哲学.它自带了一系列在Web开发中用于解决常见问题或需求的额外的 ...

  9. Django中添加富文本编辑器

    使用的是CKeditor这个模块 1.安装: pip install django-ckeditor 2.将ckeditor注册到settings.py文件中, 并添加ckeditor的url到你项目 ...

  10. 关于购物车添加按钮的动画(vue.js)

    来自:https://segmentfault.com/a/1190000009294321 (侵删) git 源码地址  https://github.com/ustbhuangyi/vue-sel ...

随机推荐

  1. Pycharm2018中DataBase的使用

    1.点击右侧边栏的DataBase,在出现的Database窗口下点击绿色小加号,选择Data Source,选择需要的数据库类型,此处选择Sqlite 2.配置数据库连接信息 3.选择schema, ...

  2. PAT 1093

    The string APPAPT contains two PAT's as substrings. The first one is formed by the 2nd, the 4th, and ...

  3. redis学习(一)

    Redis学习内容: 1. 概念 2. 下载安装R 3. 命令操作 1. 数据结构 4. 持久化操作 5. 使用Java客户端操作redis 1. 概念: redis是一款高性能的NOSQL系列的非关 ...

  4. 第1课(续集),python turtle库的使用

    原文再续,书接上一回 上回讲到了,python IDLE的草稿本和作业本,并顺便试了试python的输入输出,变量,运算的体验,大家应该能感受到python的简单了吧. 下面我们继续体验python的 ...

  5. S02_CH12_ AXI_Lite 总线详解

    S02_CH12_ AXI_Lite 总线详解 12.1前言 ZYNQ拥有ARM+FPGA这个神奇的架构,那么ARM和FPGA究竟是如何进行通信的呢?本章通过剖析AXI总线源码,来一探其中的秘密. 1 ...

  6. Java之数据类型讲解

    Java数据类型关系图 基本数据类型 从小到大的关系图: 图中从左向右的转换都是隐式转换,无需再代码中进行强制转换 : byte i = 12; System.out.println("by ...

  7. Windows 上的应用程序在运行期间可以给自己改名(可以做 OTA 自我更新)

    原文:Windows 上的应用程序在运行期间可以给自己改名(可以做 OTA 自我更新) 程序如何自己更新自己呢?你可能会想到启动一个新的程序或者脚本来更新自己.然而 Windows 操作系统允许一个应 ...

  8. 解决打开IE报错“无法启动...丢失api-ms-win-core-path-l1-1-0.dll”的问题

    打开IE突然发现报错 试了各种方法都不行 最终看这篇文章,才解决:https://www.yijile.com/log/577.html 打开IE设置选项,选择管理加载项,如图讲该选项禁用,就不报错. ...

  9. 使用vue-cli搭建vue项目问题解决方案

    工欲善其事必先利其器,安装所需环境 node和npm的安装 首先需要安装node环境,直接到官网下载安装包 https://nodejs.org/zh-cn/ 安装node默认安装npm, 不需要重复 ...

  10. 83.基于Vue SEO的四种方案(小结)

    前言:众所周知,Vue SPA单页面应用对SEO不友好,当然也有相应的解决方案,下面列出几种最近研究和使用过的SEO方案,SRR和静态化基于Nuxt来说. 1.SSR服务器渲染:2.静态化:3.预渲染 ...