zoukankan      html  css  js  c++  java
  • Django+Vue打造购物网站(十)

    首页、商品数量、缓存和限速功能开发

    将环境切换为本地,vue也切换为本地

    轮播图

    goods/serializers.py

    class BannerSerializer(serializers.ModelSerializer):
        '''
        轮播图
        '''
    
        class Meta:
            model = Banner
            fields = "__all__"
    

    goods/views.py

    class BannerViewset(mixins.ListModelMixin, viewsets.GenericViewSet):
        """
        首页轮播图
        """
        queryset = Banner.objects.all().order_by("index")
        serializer_class = BannerSerializer
    

    urls.py

    # 配置首页轮播图的url
    router.register(r'banners', BannerViewset, base_name="banners")
    

    新品推荐功能

    在设计Goods model时候有一个字段is_new

        is_new = models.BooleanField(default=False, verbose_name="是否新品")
    

    实现这个接口只要在goods/filters/GoodsFilter里面添加一个过滤就可以了

        class Meta:
            model = Goods
            fields = ['pricemin', 'pricemax','is_hot','is_new']
    

    首页商品分类显示功能

    goods/serializers.py

    class BrandSerializer(serializers.ModelSerializer):
        '''
        大类下面的宣传商标
        '''
    
        class Meta:
            model = GoodsCategoryBrand
            fields = "__all__"
    
    
    class IndexCategorySerializer(serializers.ModelSerializer):
        # 某个大类的商标,可以有多个商标,一对多的关系
        brands = BrandSerializer(many=True)
        # good有一个外键category,但这个外键指向的是三级类,直接反向通过外键category(三级类),取某个大类下面的商品是取不出来的
        goods = serializers.SerializerMethodField()
        # 在parent_category字段中定义的related_name="sub_cat"
        # 取二级商品分类
        sub_cat = CategorySerializer2(many=True)
        # 广告商品
        ad_goods = serializers.SerializerMethodField()
    
        def get_ad_goods(self, obj):
            goods_json = {}
            ad_goods = IndexAd.objects.filter(category_id=obj.id, )
            if ad_goods:
                # 取到这个商品Queryset[0]
                good_ins = ad_goods[0].goods
                # 在serializer里面调用serializer的话,就要添加一个参数context(上下文request),
                # 否则图片链接是不完整的
                # 嵌套serializer必须加
                # serializer返回的时候一定要加 “.data” ,这样才是json数据
                goods_json = GoodsSerializer(good_ins, many=False, context={'request': self.context['request']}).data
            return goods_json
    
        # 自定义获取方法
        def get_goods(self, obj):
            # 将这个商品相关父类子类等都可以进行匹配
            all_goods = Goods.objects.filter(Q(category_id=obj.id) | Q(category__parent_category_id=obj.id) | Q(
                category__parent_category__parent_category_id=obj.id))
            goods_serializer = GoodsSerializer(all_goods, many=True, context={'request': self.context['request']})
            return goods_serializer.data
    
        class Meta:
            model = GoodsCategory
            fields = "__all__"
    

    goods/views.py

    class IndexCategoryViewset(mixins.ListModelMixin, viewsets.GenericViewSet):
        """
        首页商品分类数据
        """
        # 获取is_tab=True(导航栏)里面的分类下的商品数据
        queryset = GoodsCategory.objects.filter(is_tab=True, name__in=["生鲜食品", "酒水饮料"])
        serializer_class = IndexCategorySerializer
    

    urls.py

    # 首页系列商品展示url
    router.register(r'indexgoods', IndexCategoryViewset, base_name="indexgoods")
    

    热搜词

    goods/serializers.py

    class HotWordsSerializer(serializers.ModelSerializer):
        class Meta:
            model = HotSearchWords
            fields = "__all__"
    

    goods/views.py

    class HotSearchsViewset(mixins.ListModelMixin, viewsets.GenericViewSet):
        """
        获取热搜词列表
        """
        queryset = HotSearchWords.objects.all().order_by("-index")
        serializer_class = HotWordsSerializer
    

    urls.py

    # 首页热搜词
    router.register(r'hotsearchs', HotSearchsViewset, base_name="hotsearchs")
    

    商品点击数和收藏数

    GoodsListViewSet其中继承了mixins.RetrieveModelMixin
    只需要重写retrieve方法即可

    class GoodsListViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
        '''
        商品列表页, 分页, 过滤, 排序
        '''
        queryset = Goods.objects.all().order_by('id')
        serializer_class = GoodsSerializer
        pagination_class = GoodsPagination
        filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
    
        # authentication_classes = (TokenAuthentication,)
        # 自定义过滤器
        filter_class = GoodsFilter
        # 搜索,默认模糊查询
        search_fields = ('name', 'goods_brief')
        # 排序
        ordering_fields = ('sold_num', 'shop_price')
    
        # 商品点击数 + 1
        def retrieve(self, request, *args, **kwargs):
            instance = self.get_object()
            instance.click_num += 1
            instance.save()
            serializer = self.get_serializer(instance)
            return Response(serializer.data)
    

    UserFavViewset继承了mixins.CreateModelMixin
    重写perform_create方法即可

    class UserFavViewset(viewsets.GenericViewSet, mixins.ListModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin):
        '''
        list:
            获取用户的所有收藏
        create:
            添加收藏
        destroy:
            取消收藏
        '''
        # permission是用来做权限判断的
        # IsAuthenticated:必须登录用户;IsOwnerOrReadOnly:必须是当前登录的用户
        permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
        # auth使用来做用户认证的
        authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
        # 搜索的字段
        lookup_field = 'goods_id'
    
        def get_queryset(self):
            # 只能查看当前登录用户的收藏,不会获取所有用户的收藏
            return UserFav.objects.filter(user=self.request.user)
    
        # 动态选择serializer
        def get_serializer_class(self):
            if self.action == "list":
                return UserFavDetailSerializer
            elif self.action == "create":
                return UserFavSerializer
            return UserFavSerializer
    
        # 用户收藏的商品数量+1
        def perform_create(self, serializer):
            instance = serializer.save()
            # 这里instance相当于UserFav model,通过它找到goods
            goods = instance.goods
            goods.fav_num += 1
            goods.save()
    

    用信号量实现收藏数变化
    delete和create的时候django model都会发送一个信号量出来,用信号量的方式代码分离性更好

    user_operation/signals.py

    from django.db.models.signals import post_delete, post_save
    from django.dispatch import receiver
    
    from user_operation.models import UserFav
    
    
    # post_save : model变化方式
    # sender : 变动的model
    @receiver(post_save, sender=UserFav)
    def create_userfav(sender, instance=None, created=False, **kwargs):
        if created:
            goods = instance.goods
            goods.fav_num += 1
            goods.save()
    
    
    @receiver(post_delete, sender=UserFav)
    def delete_userfav(sender, instance=None, created=False, **kwargs):
        goods = instance.goods
        goods.fav_num -= 1
        goods.save()
    

    user_operation/apps.py

    from django.apps import AppConfig
    
    
    class UserOperationConfig(AppConfig):
        name = 'user_operation'
        verbose_name = "用户操作管理"
    
        def ready(self):
            import user_operation.signals
    

    商品库存和销量修改

    引起商品库存数量变化的行为:

    • 新增商品到购物车
    • 修改购物车数量
    • 删除购物车记录

    trade/views.py

    class ShoppingCartViewset(viewsets.ModelViewSet):
        """
        购物车功能
        list:
            获取购物车详情
        create:
            加入购物车
        delete:
            删除购物记录
        """
        permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
        authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
    
        # serializer_class = ShopCartSerializer
        lookup_field = "goods_id"
    
        def get_queryset(self):
            return ShoppingCart.objects.filter(user=self.request.user)
    
        def get_serializer_class(self):
            if self.action == 'list':
                return ShopCartDetailSerializer
            else:
                return ShopCartSerializer
    
        # 库存数-n
        def perform_create(self, serializer):
            shop_cart = serializer.save()
            goods = shop_cart.goods
            goods.goods_num -= shop_cart.nums
            goods.save()
    
        # 库存数+n
        def perform_destroy(self, instance):
            goods = instance.goods
            goods.goods_num += instance.nums
            goods.save()
            instance.delete()
    
        # 更新库存,修改可能是增加页可能是减少
        def perform_update(self, serializer):
            # 首先获取修改之前的库存数量
            existed_record = ShoppingCart.objects.get(id=serializer.instance.id)
            existed_nums = existed_record.nums
            # 先保存之前的数据existed_nums
            saved_record = serializer.save()
            # 变化的数量
            nums = saved_record.nums - existed_nums
            goods = saved_record.goods
            goods.goods_num -= nums
            goods.save()
    

    商品的销量只有在支付成功后才会 +n
    trade/views.py
    AlipayView/post方法

                # 查询数据库中订单记录
                existed_orders = OrderInfo.objects.filter(order_sn=order_sn)
                for existed_order in existed_orders:
                    # 订单商品项
                    order_goods = existed_order.goods.all()
                    # 商品销量增加订单中数值
                    for order_good in order_goods:
                        goods = order_good.goods
                        goods.sold_num += order_good.goods_num
                        goods.save()
    
                    # 更新订单状态
                    existed_order.pay_status = trade_status
                    existed_order.trade_no = trade_no
                    existed_order.pay_time = datetime.now()
                    existed_order.save()
                # 需要返回一个'success'给支付宝,如果不返回,支付宝会一直发送订单支付成功的消息
                return Response("success")
    

    drf缓存

    http://chibisov.github.io/drf-extensions/docs/#caching

    pip install drf-extensions
    

    简单使用
    在GoodsListViewSet中添加缓存功能

    from rest_framework_extensions.cache.mixins import CacheResponseMixin
    
    # CacheResponseMixin一定要放在第一个位置
    
    class GoodsListViewSet(CacheResponseMixin,mixins.ListModelMixin, mixins.RetrieveModelMixin,viewsets.GenericViewSet):
    

    设置过期时间,settings里面

    # 缓存配置
    REST_FRAMEWORK_EXTENSIONS = {
        'DEFAULT_CACHE_RESPONSE_TIMEOUT': 60*60*8   # 多少秒过期,时间自己可以随便设定
    }
    

    这个缓存使用的是内存,每次重启之后就会失效

    drf配置redis缓存

    https://django-redis-chs.readthedocs.io/zh_CN/latest/

    drf的throttle设置api的访问速率

    针对爬虫
    http://www.django-rest-framework.org/api-guide/throttling/

    settings中配置

    REST_FRAMEWORK = {
        # 限速设置
        'DEFAULT_THROTTLE_CLASSES': (
            'rest_framework.throttling.AnonRateThrottle',  # 未登陆用户
            'rest_framework.throttling.UserRateThrottle'  # 登陆用户
        ),
        'DEFAULT_THROTTLE_RATES': {
            'anon': '10/minute',  # 每分钟可以请求n次
            'user': '30/minute'  # 每分钟可以请求n次
        }
    }
    

    goods/views.py中使用

    from rest_framework.throttling import UserRateThrottle,AnonRateThrottle
    
    class GoodsListViewSet(CacheResponseMixin,mixins.ListModelMixin, mixins.RetrieveModelMixin,viewsets.GenericViewSet):
      .
      .
      throttle_classes = (UserRateThrottle, AnonRateThrottle)
    
  • 相关阅读:
    centos7安装php7
    将centos7镜像源更新为阿里镜像源
    CentOS7 vscode连接本地虚拟机vsftp服务器
    php 查看扩展,配置文件路径命令
    centos查看程序监听的端口
    centos7搭建ftp服务
    redis-事务
    kettle 执行 kjb 临时文件夹 /tmp permission denied 问题
    Spring 声明式事务与编程式事务详解
    进程和线程的区别
  • 原文地址:https://www.cnblogs.com/gaoyongjian/p/9985919.html
Copyright © 2011-2022 走看看