省市区三级联动

1. 准备省市区模型和数据

创建areas子应用

from django.db import models

class Area(models.Model):
    """省市区"""
    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

模型说明:

  • 安装子应用之后,需要迁移

      python manage.py makemigrations
      python manage.py migrate
    
  • 自关联字段的外键指向自身,所以models.ForeignKey('self')

  • 使用related_name指明父级查询子级数据的语法

    • 默认Area模型类对象.area_set语法
  • related_name='subs'

    • 现在Area模型类对象.subs语法

导入省市区数据

mysql -h数据库ip地址 -u数据库用户名 -p数据库密码 数据库 < areas.sql
mysql -h127.0.0.1 -uroot -pmysql meiduo_mall < areas.sql

总路由

# areas
path('', include('apps.areas.urls')),

子路由

from django.conf.urls import url
from . import views
urlpatterns = [


]

3. 查询省数据

1.请求方式

选项 方案
请求方法 GET
请求地址 /areas/

2.请求参数:查询参数

3.响应结果:JSON

  • 省份数据

    {
      "code":"0",
      "errmsg":"OK",
      "province_list":[
          {
              "id":110000,
              "name":"北京市"
          },
          {
              "id":120000,
              "name":"天津市"
          },
          {
              "id":130000,
              "name":"河北省"
          },
          ......
      ]
    }
    
  • 市或区数据

    {
      "code":"0",
      "errmsg":"OK",
      "sub_data":{
          "id":130000,
          "name":"河北省",
          "subs":[
              {
                  "id":130100,
                  "name":"石家庄市"
              },
              ......
          ]
      }
    }
    

4.查询省数据后端逻辑实现

from django.http import JsonResponse
from django.views import View
from apps.areas.models import Area
import logging

logger = logging.getLogger('django')

class AreasView(View):
    """省市区数据"""

    def get(self, request):
        """提供省市区数据"""

        # 提供省份数据
        try:
            # 查询省份数据
            province_model_list = Area.objects.filter(parent__isnull=True)

            # 序列化省级数据
            province_list = []
            for province_model in province_model_list:
                province_list.append({'id': province_model.id, 'name': province_model.name})
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': 400, 'errmsg': '省份数据错误'})

        # 响应省份数据
        return JsonResponse({'code': 0, 'errmsg': 'OK', 'province_list': province_list})

4. 查询市区县数据

1.请求方式

选项 方案
请求方法 GET
请求地址 /areas/<pk>/

2.请求参数:查询参数

3.响应结果:JSON

  • 市或区数据

    {
      "code":"0",
      "errmsg":"OK",
      "sub_data":{
          "id":130000,
          "name":"河北省",
          "subs":[
              {
                  "id":130100,
                  "name":"石家庄市"
              },
              ......
          ]
      }
    }
    

4.查询市区数据后端逻辑实现

class SubAreasView(View):
    """省市区数据"""

    def get(self, request,pk):
        """提供省市区数据"""

        # 提供市或区数据
        try:
            parent_model = Area.objects.get(id=pk)  # 查询市或区的父级
            sub_model_list = parent_model.subs.all()

            # 序列化市或区数据
            sub_list = []
            for sub_model in sub_model_list:
                sub_list.append({'id': sub_model.id, 'name': sub_model.name})

            sub_data = {
                'id': parent_model.id,  # 父级pk
                'name': parent_model.name,  # 父级name
                'subs': sub_list  # 父级的子集
            }
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': 400, 'errmsg': '城市或区数据错误'})

        # 响应市或区数据
        return JsonResponse({'code': 0, 'errmsg': 'OK', 'sub_data': sub_data})

5. 缓存省市区数据

提示:

  • 省市区数据是我们动态查询的结果。
  • 但是省市区数据不是频繁变化的数据,所以没有必要每次都重新查询。
  • 所以我们可以选择对省市区数据进行缓存处理。

1.缓存工具

  • from django.core.cache import cache
  • 存储缓存数据:cache.set('key', 内容, 有效期)
  • 读取缓存数据:cache.get('key')
  • 删除缓存数据:cache.delete('key')
  • 注意:存储进去和读取出来的数据类型相同,所以读取出来后可以直接使用。

2.缓存逻辑

3.缓存逻辑实现

  • 省份缓存数据
    • cache.set('province_list', province_list, 3600)
  • 市或区缓存数据
    • cache.set('sub_area_' + area_id, sub_data, 3600)