DJANGO-天天生鲜项目从0到1-009-购物车-Ajax实现添加至购物车功能

实现功能为:

在商品详情页面,选择想要购买的数量,点击“加入购物车”按钮,实现右上角的购物车数量增加,并且页面其他信息保持不变。

一般处理按钮点击后,需要重新查询刷新整个页面的信息,但是很多需求只是刷新局部或一小部分信息,因此可以通过发送Ajax请求实现,注意ajax请求都是在后台运行的,前台不会展示运行的过程。

Ajax请求过程为:

1. 前端页面发起ajax请求(这里使用jQuery)将数据传递给后端

2. 后端执行请求地址相对应的视图函数,返回json内容

3. ajax执行相应的回调函数。接收返回的json数据并执行后续操作

编辑详情页面的前端js代码

1、jQuery获取标签元素对象为:$('.classname')

2、获取子标签:$('.classname').children('标签名')

3、获取文本内容为:.text()

4、获取值属性为:.val()

5、设置标签值为在获取值的方法中加入参数,该参数就是想要设置成为的值

6、注意点击事件如果想要调用其他的方法,不能直接写成.click(function_name()),还是得写成.click(function (){function_name()}),即在匿名方法中再调用其他的方法

7、isNaN() 函数可用于判断其参数是否是 NaN,该值表示一个非法的数字。

8、发起Ajax请求写法,$.post('/cart/add/', parameter, function(data){....}) 第一个参数为请求提交的地址,第二个参数为传给后台的数据,第三个参数为回调函数,即后台处理完成后,会调用这个回调函数,参数data为后台返回的数据,在回调函数中,使用返回的数据重新设置页面的部分数据

{% block endfiles %}
<div class="add_jump"></div>

<script type="text/javascript" src="{% static 'js/jquery-1.12.4.min.js'%}"></script>
<script type="text/javascript">
//计算总价
update_goods_amout()
function update_goods_amout(){
    //获取单价
    price = $('.show_pirze').children('em').text()
    //获取数量
    count = $('.num_show').val()
    //计算总价
    amount = price * count
        //刷新界面总价
        $('.total').children('em').text(amount.toFixed(2)+'元')
}
//加号点击事件
$('.add').click(function(){
    calculate(1)
})
//减号点击事件
$('.minus').click(function(){
    calculate(-1)
})
//加减数量
function calculate(num){
    //获取原数量
    count = $('.num_show').val()
    //+-1
    count = parseInt(count) + num
    if (count <=0){
        count = 1
    }
    //刷新界面
    $('.num_show').val(count)
    //更新总价
    update_goods_amout()
}
//手动输入商品数量
$('.num_show').blur(function(){
    //获取数量
    count = $(this).val()
    //校验数量,
    if (isNaN(count) || count.trim().length==0 || parseInt(count) <=0){
        //刷新数量
        count = 1
        $(this).val(parseInt(count))
    }
    //更新总价
    update_goods_amout()
})
//获取add_cart div元素左上角的坐标
var $add_x = $('#add_cart').offset().top;
var $add_y = $('#add_cart').offset().left;
//获取show_count div元素左上角的坐标
var $to_x = $('#show_count').offset().top;
var $to_y = $('#show_count').offset().left;

//点击加入购物车的click事件
$('#add_cart').click(function(){
    //获取数量
    count = $('.num_show').val()
    //获取商品ID,手动给加入购物车按钮新增一个属性goods_id
    goods_id = $(this).attr('goods_id')
    //csrf验证信息
    csrf = $('input[name="csrfmiddlewaretoken"]').val()
    //组织参数
    parameter = {
        'goods_id': goods_id,
        'count': count,
        'csrfmiddlewaretoken': csrf
    }
    //发起Ajax请求,第三个参数function为回调函数
    $.post('/cart/add/', parameter, function(data){
        if (data.status == 'S'){
            //添加成功
            //购物车加入成功的动态效果
            $(".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.cart_count);
                        });
                });
            }
        else{
            //添加失败
            alert(data.errmsg)
        }
    })
})

</script>
{% endblock endfiles %}

编辑请求提交的URL

编辑cart应用的urls.py文件

from django.urls import path
from .views import CartView, CartAddView

urlpatterns = [
    path('add/', CartAddView.as_view(), name='add'),
    path('', CartView.as_view(), name='cart'),
]

编辑处理请求的类视图

编辑cart应用的view.py文件

1、这里判断用户是否登录时,是手动写的校验,而不是像user应用中继承LoginRequiredMixin,原因是因为如果继承了LoginRequiredMixin,谷歌浏览器按F12打开后台运行情况查看,后台确实会访问重定向到的登录页面,但是由于这里提交的是Ajax请求,前台并不会跳转成登录页面,所以用户体验来说是这个跳转是无效的。

2、获取前台传过来的商品和数量,校验成功后,将其添加至购物车redis数据库中,然后返回新的购物车数据

3、返回的是JsonResponse对象,返回值内容为json格式

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

class CartAddView(View):
    '''加入购物车处理视图'''
    def post(self, request):
        user = request.user
        context = {
            'status': 'E',
            'errmsg': ''
        }
        # 判断是否登录
        if not user.is_authenticated:
            context['errmsg'] = '用户未登录!'
            return JsonResponse(context)

        # 接收数据
        goods_id = request.POST.get('goods_id')
        count = request.POST.get('count')

        # 校验数据
        # 数据是否完整
        if not all([goods_id, count]):
            context['errmsg'] = '数据不完整!'
            return JsonResponse(context)
        # 商品是否存在
        try:
            goods_id = int(goods_id)
            goods = Goods.objects.get(id=goods_id)
        except Exception as e:
            context['errmsg'] = '用户未登录!'
            return JsonResponse(context)
        # 数量格式是否正确
        try:
            count = int(count)
        except Exception as e:
            context['errmsg'] = '商品数量格式不正确!'
            return JsonResponse(context)

        # 逻辑处理:添加购物车
        # 连接redis
        connect = get_redis_connection('default')
        cart = 'cart_%d'%(user.id)
        # 获取原购物车中goods_id的数量
        old_count = connect.hget(cart, goods_id)
        if old_count:
            count += int(old_count)
        # 判断是否超过库存
        if count > goods.onhand:
            context['errmsg'] = '超出库存数量!'
            return JsonResponse(context)
        # 将新数量保存至数据库
        connect.hset(cart, goods_id, count)
        # 获取新购物车数量
        cart_count = connect.hlen(cart)

        # 返回数据
        context['status'] = 'S'
        context['cart_count'] = cart_count
        return JsonResponse(context)
posted @ 2020-05-03 22:36  Alex-GCX  阅读(700)  评论(0编辑  收藏  举报