Django REST framework+Vue 打造生鲜超市(十二)

vue

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

13.1.轮播图接口实现

首先把pycharm环境改成本地的,vue中local_host也改成本地

(1)goods/serializer

class BannerSerializer(serializers.ModelSerializer):

'''

轮播图

'''

class Meta:

model = Banner

fields = "__all__"

(2)goods/views.py

class BannerViewset(mixins.ListModelMixin, viewsets.GenericViewSet):

"""

首页轮播图

"""

queryset = Banner.objects.all().order_by("index")

serializer_class = BannerSerializer

(3)url

# 配置首页轮播图的url

router.register(r'banners', BannerViewset, base_name="banners")

在后台添加首页轮播图图片

13.2.新品接口功能开发

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

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

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

    class Meta:

model = Goods

fields = ['pricemin', 'pricemax','is_hot','is_new']

在后台设置几个商品 is_new

13.3.首页商品分类显示功能

首先是大类,然后里面有

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

(1)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__"

(2)goods/views.py

class IndexCategoryViewset(mixins.ListModelMixin, viewsets.GenericViewSet):

"""

首页商品分类数据

"""

# 获取is_tab=True(导航栏)里面的分类下的商品数据

queryset = GoodsCategory.objects.filter(is_tab=True, name__in=["生鲜食品", "酒水饮料"])

serializer_class = IndexCategorySerializer

(3)url

# 首页系列商品展示url

router.register(r'indexgoods', IndexCategoryViewset, base_name="indexgoods")

13.4.商品点击数和收藏数

(1)点击数

GoodsListViewSet其中继承了mixins.RetrieveModelMixin(获取商品详情)

源码

class RetrieveModelMixin(object):

"""

Retrieve a model instance.

"""

def retrieve(self, request, *args, **kwargs):

instance = self.get_object()

serializer = self.get_serializer(instance)

return Response(serializer.data)

我们只要重写他的retrieve方法就可以了

goods/views

  #商品点击数 + 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)

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)

(2)收藏数

前面已经写了UserFavViewset,其中继承了mixins.CreateModelMixin,添加收藏实际就是创建数据库

这里重写它的perform_create方法就可以了

user_operation/view.py

# 用户收藏的商品数量+1

def perform_create(self, serializer):

instance = serializer.save()

# 这里instance相当于UserFav model,通过它找到goods

goods = instance.goods

goods.fav_num += 1

goods.save()

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

(3)用信号量实现

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

收藏数+1和-1

(1)user_operation/signal.py

# users_operation/signals.py

from django.db.models.signals import post_save,post_delete

from django.dispatch import receiver

from 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

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

(2)user_operation/apps.py

from django.apps import AppConfig

class UserOperationConfig(AppConfig):

name = 'user_operation'

verbose_name = "操作管理"

def ready(self):

import user_operation.signals

13.5.商品库存和销量修改

库存数量

商品库存数量的行为:

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

trade/views.py

# 库存数-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)

serializer_class = ShopCartSerializer

#商品的id

lookup_field = "goods_id"

def get_serializer_class(self):

if self.action == 'list':

return ShopCartDetailSerializer

else:

return ShopCartSerializer

#获取购物车列表

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

商品销量

商品的销量只有在支付成功后才会 +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(

app,

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(

app,

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

13.6.drf的缓存设置

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

我们用drf的一个扩展来实现缓存,github上面的使用说明:http://chibisov.github.io/drf-extensions/docs/#caching


(1)安装

pip install drf-extensions

(2)使用方法

导入

from rest_framework_extensions.cache.mixins import CacheResponseMixin

在GoodsListViewSet中添加缓存功能

#CacheResponseMixin一定要放在第一个位置

class GoodsListViewSet(CacheResponseMixin,mixins.ListModelMixin, mixins.RetrieveModelMixin,viewsets.GenericViewSet):

设置过期时间,settings里面

#缓存配置

REST_FRAMEWORK_EXTENSIONS = {

'DEFAULT_CACHE_RESPONSE_TIMEOUT': 5 #5s过期,时间自己可以随便设定

}

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

13.7.drf配置redis缓存

使用django-redis第三方库:http://django-redis-chs.readthedocs.io/zh_CN/latest/#id8 (文档说明)

(1)安装

pip install django-redis

(2)settings

# redis缓存

CACHES = {

"default": {

"BACKEND": "django_redis.cache.RedisCache",

"LOCATION": "redis://127.0.0.1:6379",

"OPTIONS": {

"CLIENT_CLASS": "django_redis.client.DefaultClient",

}

}

}

13.8.drf的throttle设置api的访问速率

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

官网使用说明:http://www.django-rest-framework.org/api-guide/throttling/

(1)settings中配置

REST_FRAMEWORK = {

#限速设置

'DEFAULT_THROTTLE_CLASSES': (

'rest_framework.throttling.AnonRateThrottle', #未登陆用户

'rest_framework.throttling.UserRateThrottle' #登陆用户

),

'DEFAULT_THROTTLE_RATES': {

'anon': '3/minute', #每分钟可以请求两次

'user': '5/minute' #每分钟可以请求五次

}

}

(2)goods/views.py中使用

from rest_framework.throttling import UserRateThrottle,AnonRateThrottle

class GoodsListViewSet(CacheResponseMixin,mixins.ListModelMixin, mixins.RetrieveModelMixin,viewsets.GenericViewSet):

  .

  .

  throttle_classes = (UserRateThrottle, AnonRateThrottle)

以上是 Django REST framework+Vue 打造生鲜超市(十二) 的全部内容, 来源链接: utcz.com/z/380642.html

回到顶部