目录

生鲜超市(一)    生鲜超市(二)    生鲜超市(三)

生鲜超市(四)    生鲜超市(五)    生鲜超市(六)

生鲜超市(七)    生鲜超市(八)    生鲜超市(九)

生鲜超市(十)    生鲜超市(十一)    生鲜超市(十二)    生鲜超市(十三)

代码下载

github

教程

学习自慕课网-前端vue结合后端DjangoFramework的在线生鲜超市

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

 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)

GoodListViewSet

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

UserFavViewset

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

ShoppingCartViewset

商品销量

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

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 打造生鲜超市(十一)

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

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

Django REST framework+Vue 打造生鲜超市(十二)的更多相关文章

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

    三.Models设计 3.1.项目初始化 (1)进虚拟环境下安装 django2.0.2 djangorestframework和相关依赖mark,filter pillow  图片处理 pip in ...

  2. Django REST framework+Vue 打造生鲜超市(三)

    四.xadmin后台管理 4.1.xadmin添加富文本插件 (1)xadmin/plugins文件夹下新建文件ueditor.py 代码如下: # xadmin/plugins/ueditor.py ...

  3. Django REST framework+Vue 打造生鲜超市(四)

    五.商品列表页 5.1.django的view实现商品列表页 (1)goods/view_base.py 在goods文件夹下面新建view_base.py,为了区分django和django res ...

  4. Django REST framework+Vue 打造生鲜超市(五)

    六.商品类别数据展示 6.1. 商品类别数据接口 (1)商品分类有两个接口: 一种是全部分类:一级二级三级 一种是某一类的分类以及商品详细信息: 开始写商品分类的接口 (2)序列化 给分类添加三级分类 ...

  5. Django REST framework+Vue 打造生鲜超市(十一)

    十二.支付宝沙箱环境配置 12.1.创建应用 进入蚂蚁金服开放平台(https://open.alipay.com/platform/home.htm),登录后进入管理中心-->>应用列表 ...

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

    十一.pycharm远程代码调试 第三方登录和支付,都需要有服务器才行(回调url),我们可以用pycharm去远程调试服务器代码 服务器环境搭建 以全新阿里云centos7系统为例: 11.1.阿里 ...

  7. Django REST framework+Vue 打造生鲜超市(一)

    一.项目介绍 1.1.掌握的技术 Vue + Django Rest Framework 前后端分离技术 彻底玩转restful api 开发流程 Django Rest Framework 的功能实 ...

  8. Django REST framework+Vue 打造生鲜超市(六)

    七.用户登录与手机注册 7.1.drf的token (1)INSTALL_APP中添加 INSTALLED_APPS = ( ... 'rest_framework.authtoken' ) toke ...

  9. Django REST framework+Vue 打造生鲜超市(十三)

    目录 生鲜超市(一)    生鲜超市(二)    生鲜超市(三) 生鲜超市(四)    生鲜超市(五)    生鲜超市(六) 生鲜超市(七)    生鲜超市(八)    生鲜超市(九) 生鲜超市(十) ...

随机推荐

  1. Algorithm --> 邮票连续组合问题

    邮票组合问题 有四种面值的邮票很多枚,面值分别为1,4,12,21,取五张,求取出这些邮票的最大连续组合值 代码: #include <stdio.h> #include <stri ...

  2. 基于docker 部署 canvas-lms

    准备:  一台8G内存的服务器.安装好docker, pull一个ubuntu镜像下来, 可以是最新版也可以是官方支持的14/ 16 Step 1: 启动docker容易加载ubuntu镜像.命令如下 ...

  3. ava集合---ArrayList的实现原理

    一.ArrayList概述 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存 ArrayList不是线程安全的,只能用在单线程环境下,多 ...

  4. hibernate的一级和二级缓存

    一级缓存就是Session级别的缓存,close后就没了. 二级缓存就是SessionFactory级别的缓存,全局缓存,要配置其他插件. 什么样的数据适合存放到第二级缓存中? 1.很少被修改的数据 ...

  5. WCF配置问题(配置WCF跨域)

    其它的先放一边.今天先来分享一下前段时间给公司做网站WCF服务接口的心得. 配置文件的配置问题 这里既然讨论WCF配置文件的问题,那么怎么创建的就不一一讲解了.好多博主都有提过的.所以直接分享自己开发 ...

  6. 冲刺每日报告--Day1

    敏捷冲刺每日报告--Day1 情况简介 由于李世钰同学出差了,周六才能回来.所以我们只能先写爬虫,封装代码提供接口等他回来调用. 任务进度 赵坤:编写了基本爬虫代码,目前能在国内有版权的B站.爱奇艺中 ...

  7. Flask 文件和流

    当我们要往客户端发送大量的数据比较好的方式是使用流,通过流的方式来将响应内容发送给客户端,实现文件的上传功能,以及如何获取上传后的文件. 响应流的生成 Flask响应流的实现原理就是通过Python的 ...

  8. DNS搜索过程

    以www.renyi.com为例 一:客户端首先检查本地HOST文件,是否有对应的IP地址,如果有,客户端直接访问,如果没有,则执行下一步. 二:客户端查看本地缓存信息,是否有对应的IP地址,如果有, ...

  9. javascript中数组的深拷贝的方法

    一.什么是浅拷贝 在js当中,我们常常遇到数组复制的的情况,许多人一般都会使用"="来直接把一个数组赋值给一个变量,如 var a=[1,2,3]; var b=a; consol ...

  10. Python内置函数(34)——filter

    英文文档: filter(function, iterable) Construct an iterator from those elements of iterable for which fun ...