收货地址--实现省市区三级联动和使用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(rareas, 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及数据)

Android省市区三级联动滚轮选择(真实项目中提取出来的组件)

Android之省市区三级联动

原生JavaScript的省市县三级联动

vue mint-ui 实现省市区街道4级联动(仿淘宝京东收货地址4级联动)