收货地址--实现省市区三级联动和使用drf-extensions扩展使用缓存
Posted cl-python
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了收货地址--实现省市区三级联动和使用drf-extensions扩展使用缓存相关的知识,希望对你有一定的参考价值。
主要实现省市区三级联动和在Django REST framework中使用缓存。
在用户录入地址时,需要进行省市区的选择。在页面加载时,向后端请求省份数据,当用户选择确定省份后,向后端请求该省份的城市数据;在用户选择确定城市数据后,向后端请求该城市的区县信息。我们把这个过程称为省市区三级联动。
我们新建一个应用areas来实现省市区三级联动。
1)终端:cd meiduo_mall/meiduo_mall/apps
2)创建areas子应用:python ../../manage.py startapp areas
3)在areas/models.py中,创建省市区数据表,采用自关联方式
from django.db import models class Area(models.Model): """ 行政区划 null=True:(必写项)允许省级的父级为空 blank=True:(必写项)约束将来在admin站点 parent表单里可以不填 on_delete:删除守护,比如将来需要删除某个市,如果 不做守护,会把这个市下面的区全都删掉 """ name = models.CharField(max_length=20, verbose_name=‘名称‘) parent = models.ForeignKey(‘self‘, on_delete=models.SET_NULL, related_name=‘subs‘, null=True, blank=True, verbose_name=‘上级行政区划‘) class Meta: db_table = ‘tb_areas‘ verbose_name = ‘行政区划‘ verbose_name_plural = ‘行政区划‘ def __str__(self): return self.name
说明
- 自关联字段的外键指向自身,所以
ForeignKey(‘self‘)
- 需要使用
related_name
指明查询一个行政区划的所有下级行政区划时,使用哪种语法查询,如本模型类中指明通过Area模型类对象.subs查询所有下属行政区划,而不是使用Django默认的Area模型类对象.area_set语法。
4)settings配置文件中安装应用:
INSTALLED_APPS = [ ‘areas.apps.AreasConfig‘,#省市区数据 ]
5)生成迁移文件: 终端命令--python manage.py makemigrations
执行迁移: 终端命令--python manage.py migrate
迁移到数据库后,我们向数据库中添加全国省市区数据,将areas.sql导入数据库中。我们可以将导入数据库的过程创建一个脚本,将areas.sql添加到scripts目录中,在scripts目录中创建import_areas_data_to_db.sh的shell脚本文件。打开import_areas_data_to_db.sh文件,输入:
#!/bin/bash
#mysql -h数据库ip地址 -u数据库用户名 -p 数据库密码 < areas.sql
mysql -h10.211.55.5 -uroot -p meiduo_mall < areas.sql
说明:以上代码如果想以python脚本运行,#!/bin/bash 改成 #!/usr/bin/env python
终端修改文件的执行权限:chmod +x import_areas_data_to_db.sh
然后输入执行命令导入数据:./import_areas_data_to_db.sh
文件导入数据库工作就完成喽。。。。。。
接下来要写后端接口程序了············
在 areas/views.py文件中新建视图:
from rest_framework.viewsets import ReadOnlyModelViewSet from .models import Area from . import serializers # Create your views here. # GET /areas/ ==> list # GET /areas/<pk>/ ==? retrieve class AreasViewSet(ReadOnlyModelViewSet): """提供省市区三级联动数据""" # 禁用分页 pagination_class = None # 指定要输出的数据来自哪个查询集 # queryset = Area.objects.all() def get_queryset(self): """根据请求的行为,过滤不同的行为对应的序列化器需要的数据""" if self.action == ‘list‘: return Area.objects.filter(parent=None) # 只有当parent=None 返回的是省级数据 else: return Area.objects.all() # 指定序列化器 # serializer_class = ‘序列化器‘ def get_serializer_class(self): """根据请求的行为,指定不同的序列化器""" if self.action == ‘list‘: return serializers.AreasSerializer else: return serializers.SubsAreasSerializer
新建areas/serializers.py文件新建序列化器:
from rest_framework import serializers from .models import Area class AreasSerializer(serializers.ModelSerializer): """list 行为的序列化器""" class Meta: # 指定输出的数据的模型类 model = Area # 指定输出的字段 fields = (‘id‘, ‘name‘) class SubsAreasSerializer(serializers.ModelSerializer): """retrieve行为的序列化器""" # 关联 subs = AreasSerializer(many=True, read_only=True) class Meta: # 指定输出的数据的模型类 model = Area # 指定输出的字段 subs=area_set fields = (‘id‘, ‘name‘, ‘subs‘)
新建areas/urls.py文件定义路由:
from rest_framework.routers import DefaultRouter from . import views router = DefaultRouter() router.register(r‘areas‘, views.AreasViewSet, base_name=‘areas‘) urlpatterns = [] urlpatterns += router.urls
在主业务逻辑应用的meiduo_mall/urls.py文件中添加此路由:
from django.conf.urls import url,include from django.contrib import admin urlpatterns = [ # 省市区 url(r‘^‘, include(‘areas.urls‘)), ]
接下来就是添加缓存:
省市区的数据是经常被用户查询使用的,而且数据基本不变化,所以我们可以将省市区数据进行缓存处理,减少数据库的查询次数。
在Django REST framework中使用缓存,可以通过drf-extensions
扩展来实现。
关于扩展使用缓存的文档,可参考链接http://chibisov.github.io/drf-extensions/docs/#caching
安装
pip install drf-extensions
使用方法
1) 直接添加装饰器
可以在使用rest_framework_extensions.cache.decorators中的cache_response装饰器来装饰返回数据的类视图的对象方法,如
class CityView(views.APIView):
@cache_response()
def get(self, request, *args, **kwargs):
...
cache_response装饰器可以接收两个参数
@cache_response(timeout=60*60, cache=‘default‘)
- timeout 缓存时间
- cache 缓存使用的Django缓存后端(即CACHES配置中的键名称)即选择的是redis数据库的几号数据库(一共16个数据库)
如果在使用cache_response装饰器时未指明timeout或者cache参数,则会使用配置文件中的默认配置,可以通过如下方法指明:
# DRF扩展
REST_FRAMEWORK_EXTENSIONS = {
# 缓存时间
‘DEFAULT_CACHE_RESPONSE_TIMEOUT‘: 60 * 60,
# 缓存存储
‘DEFAULT_USE_CACHE‘: ‘default‘,
}
- DEFAULT_CACHE_RESPONSE_TIMEOUT 缓存有效期,单位秒
- DEFAULT_USE_CACHE 缓存的存储方式,与配置文件中的
CACHES
的键对应。
注意,cache_response装饰器既可以装饰在类视图中的get方法上,也可以装饰在REST framework扩展类提供的list或retrieve方法上。使用cache_response装饰器无需使用method_decorator进行转换。
2)使用drf-extensions提供的扩展类
drf-extensions扩展对于缓存提供了三个扩展类:
-
ListCacheResponseMixin
用于缓存返回列表数据的视图,与ListModelMixin扩展类配合使用,实际是为list方法添加了cache_response装饰器
-
RetrieveCacheResponseMixin
用于缓存返回单一数据的视图,与RetrieveModelMixin扩展类配合使用,实际是为retrieve方法添加了cache_response装饰器
-
CacheResponseMixin
为视图集同时补充List和Retrieve两种缓存,与ListModelMixin和RetrieveModelMixin一起配合使用。
三个扩展类都是在rest_framework_extensions.cache.mixins
中。
为省市区视图添加缓存
因为省市区视图使用了视图集,并且视图集中有提供ListModelMixin和RetrieveModelMixin的扩展(由ReadOnlyModelViewSet提供),所以可以直接添加CacheResponseMixin扩展类。
修改返回省市区信息的视图:
from django.shortcuts import render from rest_framework.viewsets import ReadOnlyModelViewSet #添加缓存 from rest_framework_extensions.cache.mixins import CacheResponseMixin from .models import Area from . import serializers # GET /areas/ ==> list # GET /areas/<pk>/ ==? retrieve class AreasViewSet(CacheResponseMixin,ReadOnlyModelViewSet): """提供省市区三级联动数据""" # 禁用分页 pagination_class = None # 指定要输出的数据来自哪个查询集 # queryset = Area.objects.all() def get_queryset(self): """根据请求的行为,过滤不同的行为对应的序列化器需要的数据""" if self.action == ‘list‘: return Area.objects.filter(parent=None) # 只有当parent=None 返回的是省级数据 else: return Area.objects.all() # 指定序列化器 # serializer_class = ‘序列化器‘ def get_serializer_class(self): """根据请求的行为,指定不同的序列化器""" if self.action == ‘list‘: return serializers.AreasSerializer else: return serializers.SubsAreasSerializer
缓存数据保存位置与有效期的设置
我们想把缓存数据保存在redis中,且设置有效期,可以通过在配置文件中定义的方式来实现。
在settings配置文件中增加:
# DRF扩展 REST_FRAMEWORK_EXTENSIONS = { # 缓存时间 ‘DEFAULT_CACHE_RESPONSE_TIMEOUT‘: 60 * 60, # 缓存存储 ‘DEFAULT_USE_CACHE‘: ‘default‘, }
省级联动到此就结束了 , 下一篇继续写用户的地址管理
以上是关于收货地址--实现省市区三级联动和使用drf-extensions扩展使用缓存的主要内容,如果未能解决你的问题,请参考以下文章
WheelView实现省市区三级联动(数据库实现版本号附带完整SQL及数据)
WheelView实现省市区三级联动(数据库实现版本号附带完整SQL及数据)