您现在的位置是: 网站首页 >Django >Vue+Django REST framework前后端分离生鲜电商 Django

【Vue+DRF生鲜电商】33.数据缓存、接口访问限速功能

admin2019年8月14日 14:07 Django | Html | JavaScript | Vue 1807人已围观

Vue+Django REST framework前后端分离生鲜电商简介 Vue+Django REST framework 打造前后端分离的生鲜电商项目(慕课网视频)。 Github地址:https://github.com/xyliurui/DjangoOnlineFreshSupermarket ; Django版本:2.2、djangorestframework:3.9.2。 前端Vue模板可以直接联系我拿。

## DRF缓存功能CacheResponseMixin 加速网站访问速度,将常用的数据放在缓存中,访问这些数据优先从缓存中取。 可以访问 https://docs.djangoproject.com/zh-hans/2.2/topics/cache/ 查看Django的缓存使用方法。 但是这儿需要用的是DRF的缓存,Django的缓存不能使用。可以搜索**drf-extensions**或者访问 https://github.com/chibisov/drf-extensions 查看Django Rest Framework的扩展,功能很多,不只缓存功能。 官方文档 http://chibisov.github.io/drf-extensions/docs/ (为了能看这个文档,我爬到腾讯云上才访问到了) ### 安装drf-extensions ```bash pip install drf-extensions # 安装好后drf版本也被升级了 Successfully installed djangorestframework-3.10.2 drf-extensions-0.5.0 ``` 从 http://chibisov.github.io/drf-extensions/docs/#cacheresponsemixin 可以看到基本的使用方法 > 缓存标准viewset的 `retrieve`和`list`方法很常见。 这就是`CacheResponseMixin`存在的原因。 只需将其混合到viewset实现中,这些方法将使用`REST_FRAMEWORK_EXTENSIONS`设置中定义的函数: - *"DEFAULT\_OBJECT\_CACHE\_KEY\_FUNC"* 用于 `retrieve` 方法 - *"DEFAULT\_LIST\_CACHE\_KEY\_FUNC"* 用于 `list` 方法 默认情况下,这些函数使用`DefaultKeyConstructor`并对其进行扩展: - 使用`RetrieveSqlQueryKeyBit`获取 *"DEFAULT\_OBJECT\_CACHE\_KEY\_FUNC"* - 使用`ListSqlQueryKeyBit`和`PaginationKeyBit`为 *"DEFAULT\_LIST\_CACHE\_KEY\_FUNC"* Mixin使用方法 ```python from myapps.serializers import UserSerializer from rest_framework_extensions.cache.mixins import CacheResponseMixin class UserViewSet(CacheResponseMixin, viewsets.ModelViewSet): serializer_class = UserSerializer ``` ### 商品列表增加缓存 使用到我们的类中,修改 apps/goods/views.py 中的`GoodsListViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet)`类,`CacheResponseMixin`放在继承类的第一个。 ```python from rest_framework_extensions.cache.mixins import CacheResponseMixin class GoodsListViewSet(CacheResponseMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet): """ list: 显示商品列表,分页、过滤、搜索、排序 retrieve: 显示商品详情 """ queryset = Goods.objects.all() # 使用get_queryset函数,依赖queryset的值 serializer_class = GoodsSerializer pagination_class = GoodsPagination filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter,) # 将过滤器后端添加到单个视图或视图集 filterset_class = GoodsFilter # authentication_classes = (TokenAuthentication, ) # 只在本视图中验证Token search_fields = ('name', 'goods_desc', 'category__name') # 搜索字段 ordering_fields = ('click_num', 'sold_num', 'shop_price') # 排序 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) ``` 只需要再继承`CacheResponseMixin`,缓存就生效了。现在重启服务器,使浏览器缓存失效(因为我们第一次进入该页面,已经将数据放入缓存了,重启服务器,内存中就没了,需要重新到后台获取),然后访问 http://127.0.0.1:8000/goods/ 按F12点击Network查看加载时间。 可以看到首次访问需要437ms ![BLOG_20190814_140915_74](/media/blog/images/2019/08/BLOG_20190814_140915_74.png "博客图集BLOG_20190814_140915_74.png") 再次刷新该页面,第二次以及后面多次访问基本就是13s ![BLOG_20190814_140909_18](/media/blog/images/2019/08/BLOG_20190814_140909_18.png "博客图集BLOG_20190814_140909_18.png") 当数据量很多的时候,缓存效果就非常明显了。 但是缓存也需要设置一个过期时间,否则,每次都从缓存中获取数据,一旦数据修改之后,就不能获取更新的数据了。所以需要设置过期时间,在一段时间后,将从数据库中查询新的数据并更新缓存数据。 ### 配置缓存过期时间 文档中 http://chibisov.github.io/drf-extensions/docs/#timeout 也有相关的配置说明 修改 DjangoOnlineFreshSupermarket/settings.py 添加配置 ```python # drf-extensions配置 REST_FRAMEWORK_EXTENSIONS = { 'DEFAULT_CACHE_RESPONSE_TIMEOUT': 60 * 10 # 缓存全局过期时间(60 * 10 表示10分钟) } ``` 单位为秒,可以将它设置成5s做下测试,看是否5s后过期,加载时间变长。 对于总结:对于公共数据,大家都可以访问的,以及不经常变动的数据可以增加缓存,以减少请求时间。另外在 drf-extensions 中也有很多配置,可以根据自己的需求自定义。 ## DRF配置redis缓存后端 redis作为backend来缓存数据 对于 http://127.0.0.1:8000/goods/ 和 http://127.0.0.1:8000/goods/?format=json 以及不同的过滤参数,返回结果应该是不一样的。 访问 https://django-redis-chs.readthedocs.io/zh_CN/latest/ 可以看到 django-redis 的使用方法 ### 安装django-redis ```python pip install django-redis ``` ### 配置redis缓存后端 修改 DjangoOnlineFreshSupermarket/settings.py 增加配置 ```python # 配置 django-redis做缓存后端 CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379/1", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", # "PASSWORD": "blog.starmeow.cn" # 如果redis服务器设置了密码,配置成自己的密码 } } } ``` 当访问 http://127.0.0.1:8000/goods/ 刷新redis客户端可以看到缓存的键和数据 ![BLOG_20190814_140859_75](/media/blog/images/2019/08/BLOG_20190814_140859_75.png "博客图集BLOG_20190814_140859_75.png") 访问 http://127.0.0.1:8000/goods/?format=json 又生成了一个键 ![BLOG_20190814_140854_34](/media/blog/images/2019/08/BLOG_20190814_140854_34.png "博客图集BLOG_20190814_140854_34.png") 同样 http://127.0.0.1:8000/goods/?page=2 又会生成一个键,过期时间为 drf-extensions 中配置`REST_FRAMEWORK_EXTENSIONS`过期时间。 也就是说,在视图中配置`CacheResponseMixin`缓存后,可以使用redis作为缓存后端来存储数据。且针对不同的url以不同的参数,都会生成不同的键值,不同的键缓存不同的内存。如果没有配置`CacheResponseMixin`缓存,访问这些URL,是不会生成redis键值的。 Redis客户端工具可以访问 https://github.com/qishibo/AnotherRedisDesktopManager/releases 下载使用。 ## DRF的throttle设置API的访问速率 接口访问速率过快,会导致其它业务受影响,网站打不开,服务器压力过大的请况。 这个限速时DRF自带的功能 https://www.django-rest-framework.org/api-guide/throttling/ ,直接拿来使用即可。 ### 设置全局限制策略 可以使用`DEFAULT_THROTTLE_CLASSES`和`DEFAULT_THROTTLE_RATES`设置全局设置默认限制策略。 修改 DjangoOnlineFreshSupermarket/settings.py 在`REST_FRAMEWORK`添加配置 ```python # DRF配置 REST_FRAMEWORK = { # 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', # 'PAGE_SIZE': 5, 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', # 上面两个用于DRF基本验证 # 'rest_framework.authentication.TokenAuthentication', # TokenAuthentication,取消全局token,放在视图中进行 # 'rest_framework_simplejwt.authentication.JWTAuthentication', # djangorestframework_simplejwt JWT认证 ), # throttle对接口访问限速 'DEFAULT_THROTTLE_CLASSES': [ 'rest_framework.throttling.AnonRateThrottle', # 用户未登录请求限速,通过IP地址判断 'rest_framework.throttling.UserRateThrottle' # 用户登陆后请求限速,通过token判断 ], 'DEFAULT_THROTTLE_RATES': { 'anon': '60/minute', # 限制所有匿名未认证用户,使用IP区分用户。使用DEFAULT_THROTTLE_RATES['anon'] 来设置频次 'user': '200/minute' # 限制认证用户,使用User id 来区分。使用DEFAULT_THROTTLE_RATES['user'] 来设置频次 } } ``` `DEFAULT_THROTTLE_RATES`中使用的速度单位包括`second`, `minute`, `hour` 或者 `day`作为限流时间。 添加上面配置后,可以将配置修改`'anon': '6/minute',`,也就是每分钟匿名只允许访问6次。 ![BLOG_20190814_140845_18](/media/blog/images/2019/08/BLOG_20190814_140845_18.png "博客图集BLOG_20190814_140845_18.png") 当访问上面的所有接口,包含Api Root,总和超过6次之后,就会有限速提示 ![BLOG_20190814_140836_94](/media/blog/images/2019/08/BLOG_20190814_140836_94.png "博客图集BLOG_20190814_140836_94.png") 这是所有API调用次数总数计算,并非单个API都有指定的次数。 ### 单个API限速 还可以使用基于APIView类的视图在每个视图或每个视图集的基础上设置限制策略。 首先配置限速范围,修改 DjangoOnlineFreshSupermarket/settings.py ,注释掉全局限速,增加自定义权限 ```python # DRF配置 REST_FRAMEWORK = { # 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', # 'PAGE_SIZE': 5, 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', # 上面两个用于DRF基本验证 # 'rest_framework.authentication.TokenAuthentication', # TokenAuthentication,取消全局token,放在视图中进行 # 'rest_framework_simplejwt.authentication.JWTAuthentication', # djangorestframework_simplejwt JWT认证 ), # throttle对接口访问限速 'DEFAULT_THROTTLE_CLASSES': [ # 'rest_framework.throttling.AnonRateThrottle', # 用户未登录请求限速,通过IP地址判断 # 'rest_framework.throttling.UserRateThrottle' # 用户登陆后请求限速,通过token判断 'rest_framework.throttling.ScopedRateThrottle', # 限制用户对于每个视图的访问频次,使用ip或user id。 ], 'DEFAULT_THROTTLE_RATES': { # 'anon': '60/minute', # 限制所有匿名未认证用户,使用IP区分用户。使用DEFAULT_THROTTLE_RATES['anon'] 来设置频次 # 'user': '200/minute' # 限制认证用户,使用User id 来区分。使用DEFAULT_THROTTLE_RATES['user'] 来设置频次 'goods_list': '600/minute' } } ``` 就可以在视图中添加`throttle_scope = 'goods_list'`来达到限速目的。可以将`'goods_list': '600/minute'`修改小一点测试。 例如可以给 apps/goods/views.py 中的`GoodsListViewSet`配置限速 ```python from rest_framework.throttling import UserRateThrottle, AnonRateThrottle class GoodsListViewSet(CacheResponseMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet): """ list: 显示商品列表,分页、过滤、搜索、排序 retrieve: 显示商品详情 """ queryset = Goods.objects.all() # 使用get_queryset函数,依赖queryset的值 serializer_class = GoodsSerializer pagination_class = GoodsPagination filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter,) # 将过滤器后端添加到单个视图或视图集 filterset_class = GoodsFilter # authentication_classes = (TokenAuthentication, ) # 只在本视图中验证Token search_fields = ('name', 'goods_desc', 'category__name') # 搜索字段 ordering_fields = ('click_num', 'sold_num', 'shop_price') # 排序 # throttle_classes = [UserRateThrottle, AnonRateThrottle] # DRF默认限速类,可以仿照写自己的限速类 throttle_scope = 'goods_list' 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) ``` 现在访问 http://127.0.0.1:8000/goods/ 超限后就会提示 请求超过了限速。而其他API则不受影响。 另外可以仿照 `UserRateThrottle, AnonRateThrottle`写自己的限速类

很赞哦! (2)

文章交流

  • emoji
0人参与,0条评论

当前用户

未登录,点击   登录

站点信息

  • 建站时间:网站已运行2285天
  • 系统信息:Linux
  • 后台程序:Python: 3.8.10
  • 网站框架:Django: 3.2.6
  • 文章统计:257 篇
  • 文章评论:63 条
  • 腾讯分析网站概况-腾讯分析
  • 百度统计网站概况-百度统计
  • 公众号:微信扫描二维码,关注我们
  • QQ群:QQ加群,下载网站的学习源码
返回
顶部
标题 换行 登录
网站