商品详情页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':'删除成功'})

最新文章

  1. php实现递归的三种方式: 遍历文件夹实例
  2. Core Data数据操作
  3. $key 的用法
  4. JQuery:JQuery遍历详解
  5. MVC权限管理系统dwpro项目分配按钮没有显示的问题
  6. Java -Dfile.encoding=UTF-8 出现乱码问题原因分析
  7. Linux学习系列之Linux入门(二)Vim学习
  8. xHTML+div布局:三个div,两边div宽度固定,中间div宽度自适应
  9. Effective C++:条款37:绝不又一次定义继承而来的缺省參数值
  10. 查看内存数据的函数(ByteToHex和ByteToBin,最终都变成String)
  11. spring mvc ModelAndView向前台传值
  12. dva + antd + mockjs 实现基础用户管理
  13. V5.7_UTF8_SP1、SP2---任意前台用户登录(cookie伪造)
  14. python 访问 zookeeper
  15. 封装qq分享静态库到cocopod
  16. TOMCAT启动流程分析
  17. react子传父
  18. IE浏览器使用VLC实时显示视频(海康、大华)
  19. java中String类型
  20. Unity shader学习之Alpha Test

热门文章

  1. ASP.NET-------GridView中的字段居中不了
  2. SQL Server 类似正则表达式的字符处理问题
  3. (谷歌浏览器)前端以FormData类形成表单(含文件),通过ajax提交,PHP后端$_POST数组为空
  4. Python之路【第二十三篇】:数据库基础
  5. 2019牛客暑期多校训练营(第二场)H Second Large Rectangle
  6. HSF 开发
  7. python使用自带模块httplib进行http请求
  8. 【题解】Luogu P5294 [HNOI2019]序列
  9. powerful number求积性函数前缀和
  10. .net core 读取、修改配置文件appsettings.json