商品详情页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. netty例子-客户端每隔5秒发送查询时间的请求,服务器端响应请求

    netty是jboss公司开发的,基于异步的.事件驱动的网络应用程序框架,快速开发高性能.高可靠性的服务器和客户端程序 public class TimeServer { ; public void ...

  2. java 字符串转json,json转实体对象、json字符串转换成List、List转String、以及List排序等等...

    @RequestMapping(value = "updateInvestorApplyAccountNo", method = RequestMethod.POST) @Resp ...

  3. Django-11-Form组件

    1. 概述 Django的Form组件一般功能有: 验证用户输入 生成html代码 返回错误信息 创建Form类 from django.shortcuts import render, redire ...

  4. 实现一个 web 服务器

    在 system1 上配置一个站点 http://system1.group8.example.com/,然后执行下述步骤: 1.从 http://server.group8.example.com/ ...

  5. python 打包前三天日志

    日志格式 app-2019-07-24.log app-2019-07-24.1.log 该脚本适合一天之内有多个日志文件 # /usr/bin/python #-*- coding: utf-8 - ...

  6. .NET/C# 如何获取当前进程的 CPU 和内存占用?如何获取全局 CPU 和内存占用?

    原文:.NET/C# 如何获取当前进程的 CPU 和内存占用?如何获取全局 CPU 和内存占用? 都知道可以在任务管理器中查看进程的 CPU 和内存占用,那么如何通过 .NET 编写代码的方式来获取到 ...

  7. (转)微服务_.NET Core Consul服务发现与治理

    原文地址:https://www.cnblogs.com/waynechan/p/9354909.html Consul官网:https://www.consul.io Consul下载地址:http ...

  8. Python进阶----进程间数据隔离, join阻塞等待, 进程属性, 僵尸进程和孤儿进程, 守护进程

    Python进阶----进程间数据隔离, join阻塞等待, 进程属性, 僵尸进程和孤儿进程, 守护进程 一丶获取进程以及父进程的pid 含义:    进程在内存中开启多个,操作系统如何区分这些进程, ...

  9. 为什么UDP有时比TCP更有优势?

    随着网络技术飞速发展,网速已不再是传输的瓶颈,UDP协议以其简单.传输快的优势,在越来越多场景下取代了TCP.1.网速的提升给UDP稳定性提供可靠网络保障 CDN服务商Akamai(NASDAQ: A ...

  10. Django:实现读写分离

    库的配置 1.读写分离 settings配置 #settings.py 配置库信息,生成2个库 DATABASES = { 'default': { 'ENGINE': 'django.db.back ...