博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
vue+django2.0.2-rest-framework 生鲜项目(九)
阅读量:5011 次
发布时间:2019-06-12

本文共 14907 字,大约阅读时间需要 49 分钟。

vue+django2.0.2-rest-framework 生鲜项目


 一、首页相关-细节完善

 1、首页轮播图

 1)goods/serializers.py:新增轮播图序列化

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

 

2)goods/views.py:新增首页轮播图view

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

 

3)url配置:

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

 


 

2、首页-新品模块

使用的是url是goods(商品)下的url路由,所以只需要在filter(过滤器)中加上字段:is_new ,就可以了

class GoodsFilter(django_filters.rest_framework.FilterSet):    '''    自定义过滤器,实现区间过滤    商品过滤的类    '''    ……    class Meta:        model = Goods        fields = ['pricemin', 'pricemax','top_category','is_hot','is_new']   # 新增‘is_new’字段

 


 

3、首页商品分类显示功能

首先是大类,然后里面有

  • 商品商标(多个)
  • 大类下的二级类
  • 广告商品
  • 所有商品

 

1)goods/models.py中新增表:

class IndexAd(models.Model):    """    首页类别标签右边展示的七个商品广告    """    category = models.ForeignKey(GoodsCategory, on_delete=models.CASCADE, related_name='category',verbose_name="商品类目")    goods =models.ForeignKey(Goods, on_delete=models.CASCADE, related_name='goods')    class Meta:        verbose_name = '首页广告'        verbose_name_plural = verbose_name    def __str__(self):        return self.goods.name

 

2)goods/xadmin.py:注册IndexAd

class IndexAdAdmin(object):    list_display = ["category", "goods"]xadmin.site.register(IndexAd, IndexAdAdmin)

 

3)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__"

 

4)goods/views.py:

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

 

5)urls.py配置:

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

 

4、商品点击数跟收藏数 

 1)点击数

GoodsListViewSet其中继承了mixins.RetrieveModelMixin(获取商品详情),当用户访问某个商品详情时,让商品点击数加1 重写retrieve()方法
#商品点击数 + 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)

 

完整代码:

goods/views.py/GoodsListViewSet:

class GoodsListViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin,viewsets.GenericViewSet):    '''    list:        商品列表,分页,搜索,过滤,排序    retrieve:        获取商品详情    '''    # authentication_classes = (TokenAuthentication,)    #这里必须要定义一个默认的排序,否则会报错    queryset = Goods.objects.all().order_by('id')    # 分页    pagination_class = GoodsPagination    #序列化    serializer_class = GoodsSerializer    filter_backends = (DjangoFilterBackend,filters.SearchFilter,filters.OrderingFilter)    # 设置filter的类为我们自定义的类    #过滤    filter_class = GoodsFilter    #搜索    search_fields = ('name', 'goods_brief', 'goods_desc')    #排序    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)
GoodsListViewSet

 

2)商品收藏数

两种方法处理,第一种是重写源码相应方法,如:添加收藏,用户点击收藏时,相当于创建了收藏表数据,重写mixins.CreateModelMixin的perform_create方法就可以了:

user_operation/view.py下的UserFavViewset:

# 用户收藏的商品数量+1    def perform_create(self, serializer):        instance = serializer.save() # 拿到的当前对象是收藏对象,封装着user、goods        goods = instance.goods        goods.fav_num += 1        goods.save()

 

完整代码: 

 user_operation/view.py/UserFavViewset

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

用户取消收藏,商品收藏数减1,重写mixins.DestroyModelMixin下的perform_destroy(self, instance)方法,也是可以实现收藏数减1,具体实现可以自己尝试。

 

第二种方法是用信号量处理,代码分离性比较好,不需要在views逻辑页面中修改代码,比较推荐这种。

首先,在user_operation下新建py文件:signal.py,代码如下:

 post_save:前面章节有介绍过,跟下面的一样,都是用来接收信号的方式。当数据被create或update时会触发此方法

 post_delete:当数据被删除时会触发此方法

# users_operation/signals.pyfrom django.db.models.signals import post_save,post_deletefrom django.dispatch import receiverfrom user_operation.models import UserFav# post_save:接收信号的方式#sender: 接收信号的model@receiver(post_save, sender=UserFav)def create_UserFav(sender, instance=None, created=False, **kwargs):    # 是否新建收藏,因为update的时候也会进行post_save,新建才让goods收藏+1    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中添加代码: 

def ready(self):        import user_operation.signals
from django.apps import AppConfigclass UserOperationConfig(AppConfig):    name = 'user_operation'    verbose_name = "操作管理"    def ready(self):   # 新增        import user_operation.signals

这样便完成了收藏 ± 1 操作


 

5、商品库存和销量修改

1)商品库存数量的行为

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

以重新方法的方式:

  • CreateModelMixin/perform_create() 方法
  • UpdateModelMixin/perform_update() 方法
  • DestroyModelMixin/perform_destroy() 方法

trade/views.py/ShoppingCartViewset:

# 库存数-1    def perform_create(self, serializer):        shop_cart = serializer.save()        goods = shop_cart.goods        goods.goods_num -= shop_cart.nums        goods.save()    # 库存数+1    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()

 

完整代码:

class ShoppingCartViewset(viewsets.ModelViewSet):    """    购物车功能    list:        获取购物车详情    create:        加入购物车    delete:        删除购物记录    """    permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)    authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)    def get_serializer_class(self):        if self.action == 'list':            return ShopCartDetailSerializer        else:            return ShopCartSerializer    lookup_field = "goods_id"    def get_queryset(self):        return ShoppingCart.objects.filter(user=self.request.user)# 库存数-1    def perform_create(self, serializer):        shop_cart = serializer.save()        goods = shop_cart.goods        goods.goods_num -= shop_cart.nums        goods.save()    # 库存数+1    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()
ShoppingCartViewset

 

2)销量修改

商品的销量只有在支付成功后才会 +1

trade/views.py:

for order_good in order_goods:                    goods = order_good.goods                    goods.sold_num += order_good.goods_num                    goods.save()

 

完整代码:

class AlipayView(APIView):    def get(self, request):        """        处理支付宝的return_url返回        """        processed_dict = {}        # 1. 获取GET中参数        for key, value in request.GET.items():            processed_dict[key] = value        # 2. 取出sign        sign = processed_dict.pop("sign", None)        # 3. 生成ALipay对象        alipay = AliPay(            appid="2016091500517456",            app_notify_url="http://47.93.198.159:8000/alipay/return/",            app_private_key_path=private_key_path,            alipay_public_key_path=ali_pub_key_path,  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,            debug=True,  # 默认False,            return_url="http://47.93.198.159:8000/alipay/return/"        )        verify_re = alipay.verify(processed_dict, sign)        # 这里可以不做操作。因为不管发不发return url。notify url都会修改订单状态。        if verify_re is True:            order_sn = processed_dict.get('out_trade_no', None)            trade_no = processed_dict.get('trade_no', None)            trade_status = processed_dict.get('trade_status', None)            existed_orders = OrderInfo.objects.filter(order_sn=order_sn)            for existed_order in existed_orders:                existed_order.pay_status = trade_status                existed_order.trade_no = trade_no                existed_order.pay_time = datetime.now()                existed_order.save()            response = redirect("/index/#/app/home/member/order")            return response        else:            response = redirect("index")            return response    def post(self, request):        """        处理支付宝的notify_url        """        #存放post里面所有的数据        processed_dict = {}        #取出post里面的数据        for key, value in request.POST.items():            processed_dict[key] = value        #把signpop掉,文档有说明        sign = processed_dict.pop("sign", None)        #生成一个Alipay对象        alipay = AliPay(            appid="2016091500517456",            app_notify_url="http://47.93.198.159:8000/alipay/return/",            app_private_key_path=private_key_path,            alipay_public_key_path=ali_pub_key_path,  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,            debug=True,  # 默认False,            return_url="http://47.93.198.159:8000/alipay/return/"        )        #进行验证        verify_re = alipay.verify(processed_dict, sign)        # 如果验签成功        if verify_re is True:            #商户网站唯一订单号            order_sn = processed_dict.get('out_trade_no', None)            #支付宝系统交易流水号            trade_no = processed_dict.get('trade_no', None)            #交易状态            trade_status = processed_dict.get('trade_status', None)            # 查询数据库中订单记录            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")
AlipayView

 

6、drf的缓存设置

为了加速网站的访问速度,将一些数据放到缓存当中,取数据的时候首先去缓存中去,然后再去数据库中取

我们用drf的一个扩展来实现缓存,github上面的使用说明:

一般在retrieve、list,有这两种方法需求的情况下需要缓存设置

 

 

 

使用:

 1)安装:

pip install drf-extensions

2)view中使用:

 导入模块:

from rest_framework_extensions.cache.mixins import CacheResponseMixin

 在GoodsListViewSet中添加缓存功能:  

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

 

3)设置过期时间,settings里面:

#缓存配置REST_FRAMEWORK_EXTENSIONS = {    'DEFAULT_CACHE_RESPONSE_TIMEOUT': 5   # 5秒过期    # 'DEFAULT_CACHE_RESPONSE_TIMEOUT': 60 *5   #5分钟过期}

 

注意:上述缓存是存于内存中的,未写入磁盘,如果系统断电或者重启,缓存就不存在了。


7、drf配置redis缓存  

 使用django-redis第三方库

  中文文档:

 使用:

 1)安装:

pip install django-redis

 

2)setting中配置:

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

 

8、drf的throttle设置api的访问速率

为了防止爬虫对服务器造成的重大压力,对数据进行访问速率限制就显得非常的重要了。

官方文档:

 throttle是drf自带的模块,因此不需要安装第三方包

使用:

 1)setting配置:

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

 

2)goods/views.py/GoodsListViewSet中使用 :

from rest_framework.throttling import UserRateThrottle,AnonRateThrottleclass GoodsListViewSet(CacheResponseMixin,mixins.ListModelMixin, mixins.RetrieveModelMixin,viewsets.GenericViewSet):  .  .  throttle_classes = (UserRateThrottle, AnonRateThrottle)

 

 

转载于:https://www.cnblogs.com/Eric15/articles/9649714.html

你可能感兴趣的文章
JS基础回顾,小练习(判断数组,以及函数)
查看>>
多任务——进程
查看>>
WCF:如何将net.tcp协议寄宿到IIS
查看>>
WebAPI HelpPage支持area
查看>>
Path元素
查看>>
php_soap扩展应用
查看>>
第二百三十一节,Bootstrap 介绍
查看>>
vi/vim 三种模式的操作
查看>>
JAVA面向对象三大特性总结
查看>>
guid
查看>>
Python中出现“TabError: inconsistent use of tabs and spaces in indentation”问题的解决
查看>>
ajax请求
查看>>
js学习总结----DOM增删改和应用
查看>>
希尔伯特矩阵(Hilbert matrix)
查看>>
(20)sopel算法
查看>>
学习总结 javascript 闭包
查看>>
实验吧一个小坑注入
查看>>
【 D3.js 高级系列 — 8.0 】 打标
查看>>
Mac必备软件推荐
查看>>
Android Gson深入分析
查看>>