天天生鲜Django项目②

07-天天生鲜首页

首页index.html 静态化

在这里插入图片描述
在这里插入图片描述
nginx访问静态页面配置
在这里插入图片描述
修改
goods.models.py

from django.contrib import admin
# Register your models here.
from django.core.cache import cache
from apps.goods.models import GoodsType, IndexPromotionBanner, IndexGoodsBanner, IndexTypeGoodsBanner


class BaseModelAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        """
        当促销页被管理员修改时,会触发modelAdmin自动的save_model方法
        在这里需要重新生成index静态文件
        """
        super(BaseModelAdmin, self).save_model(request, obj, form, change)

        # 发出任务让celery重新生成静态页面
        from celery_tasks.tasks import generate_static_index_html
        generate_static_index_html.delay()

        # 更新首页的缓存
        cache.delete('index_page_data')

    def delete_model(self, request, obj):
        """管理员删除时候更新index页面"""
        super(BaseModelAdmin, self).delete_model(request, obj)

        # 发出任务让celery重新生成静态页面
        from celery_tasks.tasks import generate_static_index_html
        generate_static_index_html.delay()

        # 更新首页的缓存
        cache.delete('index_page_data')


class IndexPromotionBannerAdmin(BaseModelAdmin):
    pass


class IndexGoodsBannerAdmin(BaseModelAdmin):
    pass


class GoodsTypeAdmin(BaseModelAdmin):
    pass


class IndexTypeGoodsBannerAdmin(BaseModelAdmin):
    pass


admin.site.register(GoodsType, GoodsTypeAdmin)
admin.site.register(IndexGoodsBanner, IndexGoodsBannerAdmin)
admin.site.register(IndexPromotionBanner, IndexPromotionBannerAdmin)
admin.site.register(IndexTypeGoodsBanner, IndexTypeGoodsBannerAdmin)

04_静态index页面和IndexView的调度说明

在这里插入图片描述

05_首页数据缓存设置和获取

缓存作用

在这里插入图片描述

index视图与Django的缓存配置

class IndexView(View):
    """首页"""

    def get(self, request):
        """
        显示首页,如果访问的是/index的话直接调用视图函数去重新查询一遍
            如果直接访问域名的话,那么加载的是celery服务器中已经渲染好的html代码,不需要数据库重新 查询
            当管理员更新后台的时候,会自动celery重新生成静态html网页,不影响使用
        """
        # 尝试从缓存中获取数据
        context = cache.get('index_page_data')
        if context is None:
            print('设置缓存')
            # 获取商品的种类信息
            types = GoodsType.objects.all()

            # 获取轮播图信息
            banners = IndexGoodsBanner.objects.all().order_by('index')

            # 获取促销信息
            promotion_banners = IndexPromotionBanner.objects.all().order_by('index')

            # 获取首页分类商品展示信息
            for type in types:
                image_banners = IndexTypeGoodsBanner.objects.filter(type=type, display_type=1).order_by('index')
                title_banners = IndexTypeGoodsBanner.objects.filter(type=type, display_type=1).order_by('index')

                type.image_banners = image_banners
                type.title_banners = title_banners

            # 上面查询出来的结果都一样,设置缓存
            context = {
                'types': types,
                'goods_banners': banners,
                'promotion_banners': promotion_banners,
            }
            ## 防止model更新时忘记删除缓存,信息永远缓存
            cache.set('index_page_data', context, 3600)
            print('缓存成功')


        # 获取首页购物车的数目
        if request.user.is_authenticated:
            conn = get_redis_connection('default')
            cart_key = 'cart_%s' % request.user.id
            cart_count = conn.hlen(cart_key)
        else:
            cart_count = 0

        context.update(cart_count=cart_count)

        return render(request, 'index.html', context=context)

更新时删除缓存

在这里插入图片描述

# Django的缓存配置
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/9",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }
}

在这里插入图片描述

缓存信息

在这里插入图片描述

总结

在这里插入图片描述

11_redis存储购物车记录分析

在这里插入图片描述
在这里插入图片描述

08-天天生鲜详情页

1. 商品详情与添加浏览记录

2. 用户历史浏览记录的添加

3. 获取同一SPU的其他规格的商品信息

在这里插入图片描述

class DetailView(View):
    """商品详情界面"""

    def get(self, request, goods_id):
		# 1.商品详情
        try:
            sku = GoodsSKU.objects.get(id=goods_id)
        except GoodsSKU.DoesNotExist as e:
            return redirect(reverse('goods:index'))

        # 获取商品的分类信息
        types = GoodsType.objects.all()
        # 获取商品的评论信息
        sku_order = OrderGoods.objects.filter(sku=sku).exclude(comment='')
        # 获取新品信息
        new_skus = GoodsSKU.objects.filter(type=sku.type).order_by('-create_time')[:2]

        # 3.获取同一spu下面的其他商品
        same_spu_skus = GoodsSKU.objects.filter(goods=sku.goods).exclude(id=goods_id)

        # 获取首页购物车的数目
        cart_count = 0
        if request.user.is_authenticated:
            conn = get_redis_connection('default')
            cart_key = 'cart_%s' % request.user.id
            cart_count = conn.hlen(cart_key)

            # 2.浏览历史中添加
            conn = get_redis_connection('default')
            history_key = 'history_%s' % request.user.id
            # 移除列表中的goods_id如果已经存在, 大于0表示从左移除几个,等于0表示移除所有存在的元素
            conn.lrem(history_key, 0, goods_id)
            # 左侧进行插入
            conn.lpush(history_key, goods_id)
            # 只保存用户最新浏览的5条数据
            conn.ltrim(history_key, 0, 4)

        context = {
            'sku': sku,
            'sku_order': sku_order,
            'types': types,
            'new_skus': new_skus,
            'cart_count': cart_count,
            'same_spu_skus': same_spu_skus,
        }

        return render(request, 'detail.html', context)
{% extends 'base_detail_list.html' %}
{% load staticfiles %}
{% block title %}天天生鲜-商品详情{% endblock title %}

{% block main_content %}
	<div class="breadcrumb">
		<a href="#">全部分类</a>
		<span>></span>
		<a href="#">{{ sku.type.name }}</a>
		<span>></span>
		<a href="#">商品详情</a>
	</div>

	<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 same_spu_skus %}
                        <li><a href="{% url 'goods:detail' sku.id %}">{{ sku.name }}</a></li>
                    {% endfor %}
                </ul>
            </div>

			<div class="total">总价:<em>16.80元</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>

	<div class="main_wrap clearfix">
		<div class="l_wrap fl clearfix">
			<div class="new_goods">
				<h3>新品推荐</h3>
				<ul>
                    {% for sku in new_skus %}
					<li>
						<a href="{% url 'goods:detail' sku.id %}"><img src="{{ sku.image.url }}"></a>
						<h4><a href="{% url 'goods:detail' sku.id %}">{{ sku.name }}</a></h4>
						<div class="prize">¥{{ sku.price }}</div>
					</li>
					{% endfor %}
				</ul>
			</div>
		</div>

		<div class="r_wrap fr clearfix">
			<ul class="detail_tab clearfix">
				<li id='tag_detail' class="active">商品介绍</li>
				<li id="tag_comment">评论</li>
			</ul>

			<div class="tab_content" id="tab_detail">
				<dl>
					<dt>商品详情:</dt>
                    <dd>{{ sku.goods.detail|safe }}</dd>
				</dl>
			</div>

            <div class="tab_content" id="tab_comment" style="display: none">
				<dl>
                    {% for order in sku_orders %}
					<dt>评论时间:{{ order.update_time }}&nbsp;&nbsp;用户名:{{ order.order.user.username }}</dt>
                    <dd>评论内容:{{ order.comment }}</dd>
                    {% endfor %}
				</dl>
			</div>
		</div>
	</div>
{% endblock main_content %}
{% block bottom %}
	<div class="add_jump"></div>
{% endblock bottom %}
{% block bottomfiles %}
	<script type="text/javascript" src="{% static 'js/jquery-1.12.4.min.js' %}"></script>
	<script type="text/javascript">
        $('#tag_detail').click(function () {
            $('#tag_comment').removeClass('active')
            $(this).addClass('active')
            $('#tab_detail').show()
            $('#tab_comment').hide()
        })

        $('#tag_comment').click(function () {
            $('#tag_detail').removeClass('active')
            $(this).addClass('active')
            $('#tab_detail').hide()
            $('#tab_comment').show()
        })

        update_goods_amount()
        // 计算商品的总价格
        function update_goods_amount() {
            // 获取商品的单价和数量
            price = $('.show_pirze').children('em').text()
            count = $('.num_show').val()
            // 计算商品的总价
            price = parseFloat(price)
            count = parseInt(count)
            amount = price*count
            // 设置商品的总价,保存两位小数
            $('.total').children('em').text(amount.toFixed(2)+'元')
        }

        // 增加商品的数量
        $('.add').click(function () {
            // 获取商品原有的数目
            count = $('.num_show').val()
            // 加1
            count = parseInt(count)+1
            // 重新设置商品的数目
            $('.num_show').val(count)
            // 更新商品的总价
            update_goods_amount()
        })

        // 减少商品的数量
        $('.minus').click(function () {
            // 获取商品原有的数目
            count = $('.num_show').val()
            // 减1
            count = parseInt(count)-1
            if (count <= 0){
                count = 1
            }
            // 重新设置商品的数目
            $('.num_show').val(count)
            // 更新商品的总价
            update_goods_amount()
        })

        // 手动输入商品的数量
        $('.num_show').blur(function () {
            // 获取用户输入的数目
            count = $(this).val()
            // 校验count是否合法
            if (isNaN(count) || count.trim().length==0 || parseInt(count) <=0){
                count = 1
            }
            // 重新设置商品的数目
            $(this).val(parseInt(count))
            // 更新商品的总价
            update_goods_amount()
        })

        // 获取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;


		$('#add_cart').click(function(){
            // 获取商品id和商品数量
            sku_id = $(this).attr('sku_id') // attr prop
            count = $('.num_show').val()

            {# 手动添加csrf进行ajax的post请求 #}
            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>
{% endblock bottomfiles %}

09-天天生鲜列表页

在这里插入图片描述

# /list/类型id/页码/?sort=排序方式
class ListView(View):
    """列表页"""

    def get(self, request, type_id, page):

        # 先验证种类信息
        try:
            type = GoodsType.objects.get(id=type_id)
        except GoodsType.DoesNotExist as e:
            return redirect(reverse('goods:index'))

        # 获取下拉的全部种类信息
        types = GoodsType.objects.all()

        # 获取排序的方式
        sort = request.GET.get('sort')
        if sort == 'price':
            skus = GoodsSKU.objects.filter(type=type).order_by('price')
        elif sort == 'hot':
            skus = GoodsSKU.objects.filter(type=type).order_by('-sales')
        else:
            sort = 'default'
            skus = GoodsSKU.objects.filter(type=type).order_by('-id')

        # 对skus数据进行分页
        paginator = Paginator(skus, 1)
        # 获取第page页的内容
        try:
            page = int(page)
        except Exception as e:
            page = 1

        if page > paginator.num_pages:
            page = 1

        # 获取第page页的page对象,废弃因为会加载所有的页码
        skus_page = paginator.page(page)

        # 控制限制的页码,只显示最多5个按钮
        # 如果总页数小于5,显示[1-页码]
        # 如果当前页是前三页,显示[1,2,3,4,5]
        # 如果当前页是后三页,显示[4,5,6,7,8] num_pages-4 到num_oages+1

        num_pages = paginator.num_pages
        if num_pages < 5:
            pages = range(1, num_pages + 1)
        elif page <= 3:
            pages = range(1, 6)
        elif num_pages - page <= 2:
            pages = range(num_pages - 4, num_pages + 1)
        else:
            pages = range(page - 2, page + 3)

        # 通过page对象获取数据
        # 获取新品信息
        new_skus = GoodsSKU.objects.filter(type=type).order_by('-create_time')[:2]

        # 获取首页购物车的数目
        cart_count = 0
        if request.user.is_authenticated:
            conn = get_redis_connection('default')
            cart_key = 'cart_%s' % request.user.id
            cart_count = conn.hlen(cart_key)

        context = {
            "sort": sort,
            "type": type,
            "types": types,
            "skus_page": skus_page, #会加载所有的页码
            "new_skus": new_skus,
            "cart_count": cart_count,
            "pages": pages,
        }

        return render(request, 'list.html', context)
{% extends 'base_detail_list.html' %}
{% block title %}天天生鲜-商品列表{% endblock title %}
{% block main_content %}
	<div class="breadcrumb">
		<a href="#">全部分类</a>
		<span>></span>
		<a href="#">{{ type.name }}</a>
	</div>

	<div class="main_wrap clearfix">
		<div class="l_wrap fl clearfix">
			<div class="new_goods">
				<h3>新品推荐</h3>
				<ul>
                    {% for sku in new_skus %}
					<li>
						<a href="{% url 'goods:detail' sku.id %}"><img src="{{ sku.image.url }}"></a>
						<h4><a href="{% url 'goods:detail' sku.id %}">{{ sku.name }}</a></h4>
						<div class="prize">¥{{ sku.price }}</div>
					</li>
                    {% endfor %}
				</ul>
			</div>
		</div>

		<div class="r_wrap fr clearfix">
			<div class="sort_bar">
				<a href="{% url 'goods:list' type.id 1 %}" {% if sort == 'default' %}class="active"{% endif %}>默认</a>
				<a href="{% url 'goods:list' type.id 1 %}?sort=price" {% if sort == 'price' %}class="active"{% endif %}>价格</a>
				<a href="{% url 'goods:list' type.id 1 %}?sort=hot" {% if sort == 'hot' %}class="active"{% endif %}>人气</a>
			</div>

			<ul class="goods_type_list clearfix">
                {% for sku in skus_page %}
				<li>
					<a href="{% url 'goods:detail' sku.id %}"><img src="{{ sku.image.url }}"></a>
					<h4><a href="{% url 'goods:detail' sku.id %}">{{ sku.name }}</a></h4>
					<div class="operate">
						<span class="prize">¥{{ sku.price }}</span>
						<span class="unit">{{ sku.price}}/{{ sku.unite }}</span>
						<a href="#" class="add_goods" title="加入购物车"></a>
					</div>
				</li>
                {% endfor %}
			</ul>

			<div class="pagenation">
                {% if skus_page.has_previous %}
				<a href="{% url 'goods:list' type.id skus_page.previous_page_number %}?sort={{ sort }}"><上一页</a>
                {% endif %}
                {% for pindex in pages %}
                    {% if pindex == skus_page.number %}
				        <a href="{% url 'goods:list' type.id pindex %}?sort={{ sort }}" class="active">{{ pindex }}</a>
                    {% else %}
				        <a href="{% url 'goods:list' type.id pindex %}?sort={{ sort }}">{{ pindex }}</a>
                    {% endif %}
				{% endfor %}
                {% if skus_page.has_next %}
				<a href="{% url 'goods:list' type.id skus_page.next_page_number %}?sort={{ sort }}">下一页></a>
                {% endif %}
			</div>
		</div>
	</div>
{% endblock main_content %}

10-天天生鲜商品搜索

01_商品搜索_全文检索概念

02_商品搜索_全文检索框架和引擎的安装和配置

settings.py
在这里插入图片描述

# 全文检索框架的配置
HAYSTACK_CONNECTIONS = {
    'default': {
        # 使用whoosh引擎
        # 'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
        'ENGINE': 'haystack.backends.whoosh_cn_backend.WhooshEngine',
        # 索引文件路径
        'PATH': os.path.join(BASE_DIR, 'whoosh_index'),
    }
}
#设置分页显示的数据量
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 1

# 当添加、修改、删除数据时,自动生成索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

03_商品搜索_生成索引文件

在这里插入图片描述

python manage.py rebuild_index

在这里插入图片描述在这里插入图片描述

04_商品搜索_全文检索的使用

https://blog.csdn.net/peng_for_csdn/article/details/90723609
在这里插入图片描述
在这里插入图片描述

05_商品搜索_更改分词方式

通过关键词查询,但无法通过详情、简介查询,所以更改其分词方式
添加ChineseAnalyzer.py
在这里插入图片描述

import jieba
from whoosh.analysis import Tokenizer, Token


class ChineseTokenizer(Tokenizer):
    def __call__(self, value, positions=False, chars=False,
                 keeporiginal=False, removestops=True,
                 start_pos=0, start_char=0, mode='', **kwargs):
        t = Token(positions, chars, removestops=removestops, mode=mode,**kwargs)
        seglist = jieba.cut(value, cut_all=True)

        for w in seglist:
            t.original = t.text = w
            t.boost = 1.0
            if positions:
                t.pos = start_pos + value.find(w)
            if chars:
                t.startchar = start_char + value.find(w)
                t.endchar = start_char + value.find(w) + len(w)
            yield t

def ChineseAnalyzer():
    return ChineseTokenizer()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

11. 购物车记录添加

01_商品详情页js代码

update_goods_amount()
        // 计算商品的总价格
        function update_goods_amount() {
            // 获取商品的单价和数量
            price = $('.show_pirze').children('em').text()
            count = $('.num_show').val()
            // 计算商品的总价
            price = parseFloat(price)
            count = parseInt(count)
            amount = price*count
            // 设置商品的总价,保存两位小数
            $('.total').children('em').text(amount.toFixed(2)+'元')
        }

        // 增加商品的数量
        $('.add').click(function () {
            // 获取商品原有的数目
            count = $('.num_show').val()
            // 加1
            count = parseInt(count)+1
            // 重新设置商品的数目
            $('.num_show').val(count)
            // 更新商品的总价
            update_goods_amount()
        })

        // 减少商品的数量
        $('.minus').click(function () {
            // 获取商品原有的数目
            count = $('.num_show').val()
            // 减1
            count = parseInt(count)-1
            if (count <= 0){
                count = 1
            }
            // 重新设置商品的数目
            $('.num_show').val(count)
            // 更新商品的总价
            update_goods_amount()
        })

        // 手动输入商品的数量
        $('.num_show').blur(function () {
            // 获取用户输入的数目
            count = $(this).val()
            // 校验count是否合法
            if (isNaN(count) || count.trim().length==0 || parseInt(count) <=0){
                count = 1
            }
            // 重新设置商品的数目
            $(this).val(parseInt(count))
            // 更新商品的总价
            update_goods_amount()
        })

02_购物车记录添加后台view

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 as e:
            return JsonResponse({'res': 3, 'errmsg': '商品不存在'})

        # 添加购物车记录, redis购物车使用的是hash类型保存的,用到hget获取key中的字典
        conn = get_redis_connection('default')
        cart_key = 'cart_%d' % user.id
        cart_count = conn.hget(cart_key, sku_id)

        if cart_count:
            count += int(cart_count)

        # sku_id存在即更新,不存在则新建
        conn.hset(cart_key, sku_id, count)

        # 验证商品的库存
        if count > sku.stock:
            return JsonResponse({'res': 4, 'errmsg': '商品库存不足'})

        # 获取购物车的数量
        total_count = conn.hlen(cart_key)

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

03_购物车记录添加前端js

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 as e:
            return JsonResponse({'res': 3, 'errmsg': '商品不存在'})

        # 添加购物车记录, redis购物车使用的是hash类型保存的,用到hget获取key中的字典
        conn = get_redis_connection('default')
        cart_key = 'cart_%d' % user.id
        cart_count = conn.hget(cart_key, sku_id)

        if cart_count:
            count += int(cart_count)

        # sku_id存在即更新,不存在则新建
        conn.hset(cart_key, sku_id, count)

        # 验证商品的库存
        if count > sku.stock:
            return JsonResponse({'res': 4, 'errmsg': '商品库存不足'})

        # 获取购物车的数量
        total_count = conn.hlen(cart_key)

        # 返回应答
        return JsonResponse({'res': 5, 'total_count': total_count, 'errmsg': '添加成功'})
{% block bottomfiles %}
	<script type="text/javascript" src="{% static 'js/jquery-1.12.4.min.js' %}"></script>
	<script type="text/javascript">
        $('#tag_detail').click(function () {
            $('#tag_comment').removeClass('active')
            $(this).addClass('active')
            $('#tab_detail').show()
            $('#tab_comment').hide()
        })

        $('#tag_comment').click(function () {
            $('#tag_detail').removeClass('active')
            $(this).addClass('active')
            $('#tab_detail').hide()
            $('#tab_comment').show()
        })

        update_goods_amount()
        // 计算商品的总价格
        function update_goods_amount() {
            // 获取商品的单价和数量
            price = $('.show_pirze').children('em').text()
            count = $('.num_show').val()
            // 计算商品的总价
            price = parseFloat(price)
            count = parseInt(count)
            amount = price*count
            // 设置商品的总价,保存两位小数
            $('.total').children('em').text(amount.toFixed(2)+'元')
        }

        // 增加商品的数量
        $('.add').click(function () {
            // 获取商品原有的数目
            count = $('.num_show').val()
            // 加1
            count = parseInt(count)+1
            // 重新设置商品的数目
            $('.num_show').val(count)
            // 更新商品的总价
            update_goods_amount()
        })

        // 减少商品的数量
        $('.minus').click(function () {
            // 获取商品原有的数目
            count = $('.num_show').val()
            // 减1
            count = parseInt(count)-1
            if (count <= 0){
                count = 1
            }
            // 重新设置商品的数目
            $('.num_show').val(count)
            // 更新商品的总价
            update_goods_amount()
        })

        // 手动输入商品的数量
        $('.num_show').blur(function () {
            // 获取用户输入的数目
            count = $(this).val()
            // 校验count是否合法
            if (isNaN(count) || count.trim().length==0 || parseInt(count) <=0){
                count = 1
            }
            // 重新设置商品的数目
            $(this).val(parseInt(count))
            // 更新商品的总价
            update_goods_amount()
        })

        // 获取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;

		//点击添加商品
		$('#add_cart').click(function(){
            // 获取商品id和商品数量
            sku_id = $(this).attr('sku_id') // attr prop
            count = $('.num_show').val()
			alert(sku_id+":"+count)
            {# 手动添加csrf进行ajax的post请求 #}
            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>
{% endblock bottomfiles %}

12-天天生鲜购物车记录更新

01_购物车js_全选_全不选_商品的选中和不选中

cart.html 选中js文件

    <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()
    })

02_购物车记录更新_后台view

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 as e:
            return JsonResponse({'res': 2, 'errmsg': '商品不存在'})

        # 更新购物车数量
        conn = get_redis_connection('default')
        cart_key = 'cart_%d' % user.id

        # sku_id存在即更新,不存在则新建
        conn.hdel(cart_key, sku_id)

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


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 as e:
            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': '商品库存不足'})

        # sku_id存在即更新,不存在则新建
        conn.hset(cart_key, sku_id, count)

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


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 as e:
            return JsonResponse({'res': 3, 'errmsg': '商品不存在'})

        # 添加购物车记录, redis购物车使用的是hash类型保存的,用到hget获取key中的字典
        conn = get_redis_connection('default')
        cart_key = 'cart_%d' % user.id
        cart_count = conn.hget(cart_key, sku_id)

        if cart_count:
            count += cart_count

        # sku_id存在即更新,不存在则新建
        conn.hset(cart_key, sku_id, count)

        # 验证商品的库存
        if count > sku.stock:
            return JsonResponse({'res': 4, 'errmsg': '商品库存不足'})

        # 获取购物车的数量
        total_count = conn.hlen(cart_key)

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


class CartInfoView(LoginRequiredMixin, View):
    """购物车页面"""
    def get(self, request):

        # 获取登录的用户
        user = request.user

        # redis获取用户购物车信息
        conn = get_redis_connection('default')
        cart_key = 'cart_%s' % user.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添加属性
            sku.amount = amount
            sku.count = count
            # 添加到列表
            skus.append(sku)

            total_count += count
            total_price += amount

        context = {
            'skus': skus,
            'total_count': total_count,
            'total_price': total_price,
        }

        render(request, 'cart.html', context)
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值