redis存储购物车记录分析

版权声明:FatPuffer https://blog.csdn.net/qq_42517220/article/details/88780722

1.什么时候添加购物车记录

       当用户浏览商品详情时添加购物车记录

detail.html

	<div class="goods_detail_con clearfix">
		<div class="goods_detail_pic fl"><img src="{{ sku.image.url }}"></div>

		<div class="goods_detail_list fr">
			<h3>{{ sku.name }}</h3>
			<p>{{ sku.desc }}</p>
			<div class="prize_bar">
				<span class="show_pirze">¥<em>{{ sku.price }}</em></span>
				<span class="show_unit">单  位:{{ sku.unite }}</span>
			</div>
			<div class="goods_num clearfix">
				<div class="num_name fl">数 量:</div>
				<div class="num_add fl">
					<input type="text" class="num_show fl" value="1">
					<a href="javascript:;" class="add fr">+</a>
					<a href="javascript:;" class="minus fr">-</a>	
				</div> 
			</div>
            <div>
                <p>其他规格:</p>
                <ul>
                    {% for sku in sama_spu_skus %}
                        <li><a href="{% url 'goods:detail' sku.id %}">{{ sku.name }}</a></li>
                    {% endfor %}
                </ul>
            </div>
			<div class="total">总价:<em>16.8元</em></div>
			<div class="operate_btn">
                {% csrf_token %}
				<a href="javascript:;" class="buy_btn">立即购买</a>
				<a href="javascript:;" sku_id="{{ sku.id }}" class="add_cart" id="add_cart">加入购物车</a>
			</div>
		</div>
	</div>

<script src="{% static 'js/jquery-1.12.4.min.js' %}"></script>
<script type="text/javascript">
	$('#add_cart').click(function(){
        // 获取商品id和数量
        sku_id = $(this).attr('sku_id')
        count = $('.num_show').val()
        csrf = $('input[name="csrfmiddlewaretoken"]').val()
        // alert(sku_id+':'+count)
        //组织参数
        params = {'sku_id': sku_id, 'count': count, 'csrfmiddlewaretoken': csrf}
        // 发起ajax post请求, 访问/cart/add, 传递参数:sku_id count
        $.post('{% url "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>

cart/urls.py

from django.conf.urls import url
from .views import CartAddView

urlpatterns = [
    url(r'^add$', CartAddView.as_view(), name='add'),  # 添加购物车
]

cart/views.py

from django.views.generic import View
from django.http import JsonResponse
from goods.models import GoodsSKU
from django_redis import get_redis_connection


class CartAddView(View):
    """添加购物车记录"""
    def post(self, request):
        user = request.user
        if not user.is_authenticated():
            # 用户未登录
            return JsonResponse({'res': 0, 'errmsg': '请先登录'})

        # 1.获取数据
        sku_id = request.POST.get('sku_id')
        count = request.POST.get('count')

        # 2.数据校验
        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': '商品不存在'})

        # 3.业务处理
        conn = get_redis_connection('default')
        cart_key = 'cart_%d' % user.id
        # 尝试先获取sku_id的值, --> hget cart_key
        # 如果获取不到返回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对应的值, 如果sku_id不存在则添加, 存在则更新
        conn.hset(cart_key, sku_id, count)

        # 统计用户购物车中的商品条目
        total_count = conn.hlen(cart_key)

        # 4.返回响应
        return JsonResponse({'res': 5, 'total_count': total_count, 'errmsg': '添加成功'})

2.什么时候获取购物车记录

       使用到购物车中数据和访问购物车页面的时候需要获取购物车记录

cart/urls.py

from django.conf.urls import url
from .views import CartAddView, CartInfoView

urlpatterns = [
    url(r'^add$', CartAddView.as_view(), name='add'),  # 添加购物车
    url(r'^$', CartInfoView.as_view(), name='show'),  # 购物车页面显示
]

cart/views.py

from django.shortcuts import render
from django.views.generic import View
from goods.models import GoodsSKU
from django_redis import get_redis_connection
from utils.mixin import LoginRequiredMixin  # 自定义的登录验证装饰器


class CartInfoView(LoginRequiredMixin, 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)

3.使用什么存储购物车记录

       redis存储购物车记录

4.分析购物车存储的记录格式

hash
'cart_用户id'{'sku_id1': 商品数量, 'sku_id2': 商品数量...}

示例:
'cart_1': {'1': 2, '2', 4}

获取用户购物车中的商品条目数
hlen

5.更新,删除购物车中商品

       当用户进入购物车页面后可以对购物车中商品数量进行修改,此时需要更新redis购物车记录

cart/cart.html

<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="{% url 'order:place' %}">
    {% for sku in skus %}
	<ul class="cart_list_td clearfix">
		<li class="col01"><input type="checkbox" name="sku_ids" value="{{ sku.id }}"></li>
		<li class="col02"><img src="{{ sku.image.url }}"></li>
		<li class="col03">{{ sku.name }}<br><em>{{ sku.price }}元/{{ sku.unit }}</em></li>
		<li class="col04">{{ sku.unit }}</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>

    <script src="{% static 'js/jquery-1.12.4.min.js' %}"></script>
    <script>

    // 计算被选中的商品的总件数和总价格
    function update_page_info() {
        // 获取所有被选中的商品
        // $('.cart_list_td').find(':checked')
        // 获取被选中的商品的父级元素
        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)
        // scherzi商品的小计
        sku_ul.children('.col07').text(amount.toFixed(2)+'元')
    }

    // 商品的全选和全不选
    $('.settlements').find(':checkbox').change(function () {
        //获取全选的checkbox的选中状态
        is_checked = $(this).prop('checked')
        // 遍历商品对应的cehckbox, 设置这些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
        // 如果被选中商品的总数量小于,所有商品数量, 将全选checkbox取消
        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请求都是异步,不会等待回调函数执行,所以当我们更新页面时,拿不到total_count
        // 发起ajax post请求, /cart/update, 传递参数:sku_id, count
        $.post('{% url "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('{% url "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>

cart/urls.py

扫描二维码关注公众号,回复: 5649970 查看本文章
from django.conf.urls import url
from .views import CartAddView, CartInfoView, CartUpdateView, CartDeleteView

urlpatterns = [
    url(r'^add$', CartAddView.as_view(), name='add'),  # 添加购物车
    url(r'^$', CartInfoView.as_view(), name='show'),  # 购物车页面显示
    url(r'^update$', CartUpdateView.as_view(), name='update'),  # 更新购物车记录
    url(r'^delete$', CartDeleteView.as_view(), name='delete'),  # 删除购物车记录
]

cart/views.py

# 更新购物车
# ajax post
# 前端传递参数:商品id(sku_id),更新数量(count)
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')

        # 2.数据校验
        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)

        # 计算用户购物车种商品总件数
        vals = conn.hvals(cart_key)
        total_count = 0
        for val in vals:
            total_count += int(val)

        # 返回应答
        return JsonResponse({'res': 5, 'total_count': total_count, 'ermsg': '更新成功'})


# 删除购物车记录
# ajax post
# 前端传递参数:商品id(sku_id)
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)

        # 计算用户购物车种商品总件数
        vals = conn.hvals(cart_key)
        total_count = 0
        for val in vals:
            total_count += int(val)

        # 返回应答
        return JsonResponse({'res': 3, 'total_count': total_count, 'errmsg': '删除成功'})

猜你喜欢

转载自blog.csdn.net/qq_42517220/article/details/88780722