收貨地址--實現省市區三級聯動和使用drf-extensions擴展使用緩存
主要實現省市區三級聯動和在Django REST framework中使用緩存。
在用戶錄入地址時,需要進行省市區的選擇。在頁面加載時,向後端請求省份數據,當用戶選擇確定省份後,向後端請求該省份的城市數據;在用戶選擇確定城市數據後,向後端請求該城市的區縣信息。我們把這個過程稱為省市區三級聯動。
我們新建一個應用areas來實現省市區三級聯動。
1)終端:cd meiduo_mall/meiduo_mall/apps
2)創建areas子應用:python ../../manage.py startapp areas
3)在areas/models.py中,創建省市區數據表,采用自關聯方式
fromdjango.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擴展使用緩存