一、购物车数据同步模块
1.定义数据同步中间件
from django.utils.deprecation import MiddlewareMixin
from carts.models import ShoppingCart
class SessionSyncMiddleware(MiddlewareMixin):
def process_response(self, request, response):
# 没有登录就不用做数据同步
# 登录情况才做数据从session同步到数据库,且重新更新session数据
user_id = request.session.get('user_id')
if user_id:
# 登录情况
session_goods = request.session.get('goods')
if session_goods:
# 1.判断session中商品是否存在于数据库中,如果存在则更新
# 2.如果不存在则创建
shop_carts = ShoppingCart.objects.filter(user_id=user_id)
# 更新购物车中的商品数量,记录更新商品的id值
data = []
for goods in shop_carts:
for se_goods in session_goods:
if se_goods[0] == goods.goods_id:
goods.nums = se_goods[1]
goods.save()
data.append(se_goods[0])
# 添加
session_goods_ids = [i[0] for i in session_goods]
add_goods_ids = list(set(session_goods_ids) - set(data))
for add_goods_id in add_goods_ids:
for session_good in session_goods:
if add_goods_id == session_good[0]:
ShoppingCart.objects.create(user_id=user_id, goods_id=add_goods_id, nums=session_good[1])
# 将数据库同步到session
new_shop_carts = ShoppingCart.objects.filter(user_id=user_id)
session_new_goods = [[i.goods_id, i.nums, i.is_select] for i in new_shop_carts]
request.session['goods'] = session_new_goods
return response
二、购物车功能模块
1.在urls.py配置文件中定义路由
from django.conf.urls import url, include
from carts import views
urlpatterns = [
# 购物车页面
url(r'^cart/', views.cart, name='cart'),
# 加入购物车
url(r'^add_cart/', views.add_cart, name='add_cart'),
# 计算购物车中的商品数量
url('^count_cart/', views.count_cart, name='count_cart'),
# 修改购物车中商品的勾选状态和商品属性
url('^change_cart/', views.change_cart, name='change_cart'),
# 删除购物车中的商品
url('^del_cart/(\d+)/', views.del_cart, name='del_cart'),
]
2.计算购物车中的商品数量
from django.http import JsonResponse
def count_cart(request):
if request.method == 'GET':
session_goods = request.session.get('goods')
count = len(session_goods) if session_goods else 0
return JsonResponse({'code': 200, 'msg': '请求成功', 'count': count})
3.修改购物车中商品的勾选状态和商品属性
from django.http import JsonResponse
def change_cart(request):
if request.method == 'POST':
# 获取前端Ajax传递的goods_id,is_select,nums
goods_id = int(request.POST.get('goods_id'))
is_select = request.POST.get('is_select')
nums = request.POST.get('nums')
# 获取session中商品的信息
session_goods = request.session.get('goods')
for goods in session_goods:
if goods_id == goods[0]:
# 修改session中的商品的数量和选择状态
goods[1] = int(nums) if nums else goods[1]
goods[2] = int(is_select) if is_select else goods[2]
request.session['goods'] = session_goods
return JsonResponse({'code': 200, 'msg': '请求成功'})
4.删除购物车中的商品
from django.http import JsonResponse, HttpResponseRedirect
from carts.models import ShoppingCart
def del_cart(request, id):
if request.method == 'GET':
user_id = request.session.get('user_id')
if user_id:
# 登录情况,删除数据库中的数据
ShoppingCart.objects.filter(user_id=user_id, goods_id=id).delete()
# 不管登录与否,删除session中的数据
session_goods = request.session.get('goods')
for goods in session_goods:
if goods[0] == int(id):
session_goods.remove(goods)
request.session['goods'] = session_goods
return HttpResponseRedirect(reverse('carts:cart'))
5.购物车页面JS代码
{% extends 'base_main.html' %}
{% block title %}
天天生鲜-购物车
{% endblock %}
{% block js %}
{% load static %}
<script type="text/javascript" src="{% static 'js/jquery-1.12.4.min.js' %}"></script>
{% endblock %}
{% block search %}
<div class="search_bar clearfix">
<a href="{% url 'goods:index' %}" class="logo fl"><img src="{% static 'images/logo.png' %}"></a>
<div class="sub_page_name fl">| 购物车</div>
<div class="search_con fr">
<input type="text" class="input_text fl" name="" placeholder="搜索商品">
<input type="button" class="input_btn fr" name="" value="搜索">
</div>
</div>
{% endblock %}
{% block content %}
<div class="total_count">全部商品<em>0</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>
{% if goods_all %}
{% for goods in goods_all %}
<ul class="cart_list_td clearfix">
<li class="col01"><input type="checkbox" name="sing_checkbox" checked></li>
<li class="col02"><img src="/media/{{ goods.0.goods_front_image }}"></li>
<li class="col03">{{ goods.0.name }}<br><em>{{ goods.0.shop_price }}/500g</em></li>
<li class="col04">500g</li>
<li class="col05" id="price_{{ goods.0.id }}">{{ goods.0.shop_price }}元</li>
<li class="col06">
<div class="num_add">
<a href="javascript:;" class="add fl" onclick="add_cart({{ goods.0.id }}, {{ goods.0.goods_nums }})">+</a>
<input type="text" class="num_show fl" value="{{ goods.1 }}" id="goods_cart_{{ goods.0.id }}" onblur="change_val({{ goods.0.id }}, {{ goods.0.goods_nums }})">
<a href="javascript:;" class="minus fl" onclick="sub_cart({{ goods.0.id }})">-</a>
</div>
</li>
<li class="col07" id="total_{{ goods.0.id }}">{{ goods.2 }}元</li>
<li class="col08"><a href="{% url 'carts:del_cart' goods.0.id %}">删除</a></li>
</ul>
{% endfor %}
{% endif %}
<ul class="settlements">
<li class="col01"><input type="checkbox" name="all_checkbox" checked></li>
<li class="col02">全选</li>
<li class="col03">合计(不含运费):<span>¥</span><em id="total_price">42.60</em><br>共计<b>2</b>件商品</li>
<li class="col04"><a href="place_order.html">去结算</a></li>
</ul>
{% endblock %}
{% block js2 %}
{% csrf_token %}
<script>
function calcTotal(){
var amountInput = $('.num_show')
var checkboxes = $('input[name="sing_checkbox"]')
var currentPrice = $('.col07')
var totalAmount = 0
var totalPrice = 0
amountInput.each(function (index) {
if (checkboxes[index].checked){
var amount = parseInt($(this).val())
totalAmount += amount
var price = parseFloat($(currentPrice[index]).text())
totalPrice += price
}
})
$('#total_price').text(totalPrice)
$('.col03 b').text(totalAmount)
}
$(function(){
calcTotal()
$('input[name="all_checkbox"]').on('click', function (evt) {
$('input[name="sing_checkbox"]').prop('checked', evt.target.checked)
calcTotal()
})
var checkBox = $('input[name="sing_checkbox"]')
$.each(checkBox, function (index, elem1) {
$(elem1).on('click', function () {
$.each(checkBox, function (index, elem2) {
if($(elem2).is(':checked') == false){
$('input[name="all_checkbox"]').prop({
'checked' : false
})
return false
}
$('input[name="all_checkbox"]').prop({
'checked' : true
})
})
calcTotal()
})
})
})
$.ajax({
url: '/carts/count_cart/',
type: 'GET',
dataType: 'JSON',
success: function (data) {
$('.total_count em').text(data.count)
},
error: function (data) {
alert('获取购物车商品数量失败')
}
})
function add_cart(goods_id, goods_nums) {
var v = $('#goods_cart_' + goods_id).val()
var new_value = parseInt(v) + 1
if (new_value <= goods_nums){
var price = parseInt($('#price_' + goods_id).text())
$('#goods_cart_' + goods_id).val(new_value)
total_price = price * new_value
$('#total_' + goods_id).text(total_price.toFixed(1)+'元')
calcTotal()
cart_ajax(goods_id)
}
}
function sub_cart(goods_id) {
var v = $('#goods_cart_' + goods_id).val()
if (v>1){
var new_value = parseInt(v) - 1
var price = parseInt($('#price_' + goods_id).text())
$('#goods_cart_' + goods_id).val(new_value)
total_price = price * new_value
$('#total_' + goods_id).text(total_price.toFixed(1)+'元')
calcTotal()
cart_ajax(goods_id)
}
}
function change_val(goods_id, goods_nums) {
var v = $('#goods_cart_' + goods_id).val()
if (parseInt(v) > 0){
if(v <= goods_nums && v > 0){
var price = parseFloat($('#price_' + goods_id).text())
var new_total = parseInt(v) * price
$('#total_' + goods_id).text(new_total.toFixed(1) + '元')
calcTotal()
cart_ajax(goods_id)
}
if (v > goods_nums){
$('#goods_cart_' + goods_id).val(goods_nums)
var v = $('#goods_cart_' + goods_id).val()
var price = parseFloat($('#price_' + goods_id).text())
var new_total = parseInt(v) * price
$('#total_' + goods_id).text(new_total.toFixed(1) + '元')
calcTotal()
cart_ajax(goods_id)
}
}else{
$('#goods_cart_' + goods_id).val(1)
var price = parseFloat($('#price_' + goods_id).text())
var new_total = 1 * price
$('#total_' + goods_id).text(new_total.toFixed(1) + '元')
calcTotal()
cart_ajax(goods_id)
}
}
function cart_ajax(goods_id) {
var nums = $('#goods_cart_' + goods_id).val()
var csrf = $('input[name="csrfmiddlewaretoken"]').val()
$.ajax({
url: '/carts/change_cart/',
type: 'POST',
data: {'goods_id': goods_id, 'nums': nums},
dataType: 'JSON',
headers: {'X-CSRFToken': csrf},
success: function (data) {
},
error: function (data) {
add_cart('失败')
}
})
}
</script>
{% endblock %}