省市区地址查询
在用户录入地址时,需要进行省市区的选择。在页面加载时,向后端请求省份数据,当用户选择确定省份后,向后端请求该省份的城市数据;在用户选择确定城市数据后,向后端请求该城市的区县信息。我们把这个过程称为省市区三级联动。
我们新建一个应用areas来实现省市区三级联动。
数据库建表
在areas/models.py中,我们创建省市区数据表,采用自关联方式。
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
说明
- 自关联字段的外键指向自身,所以
ForeignKey('self')
- 需要使用
related_name
指明查询一个行政区划的所有下级行政区划时,使用哪种语法查询,如本模型类中指明通过Area模型类对象.subs查询所有下属行政区划,而不是使用Django默认的Area模型类对象.area_set语法。
迁移到数据库后,我们向数据库中添加全国省市区数据,将areas.sql导入数据库中。
我们可以将导入数据库的过程创建一个脚本,在scripts目录中创建import_areas_data_to_db.sh文件
mysql -h数据库ip地址 -u数据库用户名 -p 数据库密码 < areas.sql
# mysql -h10.211.55.5 -umeiduo -p meiduo_mall < areas.sql
如:
#!/bin/bash
mysql -h10.211.55.5 -umeiduo -p meiduo_mall < areas.sql
修改文件的执行权限
chmod +x import_areas_data_to_db.sh
然后执行如下命令导入数据
./import_areas_data_to_db.sh
后端接口设计
1)请求省份数据
请求方式: GET /areas/
请求参数: 无
返回数据: JSON
[
{
"id": 110000,
"name": "北京市"
},
{
"id": 120000,
"name": "天津市"
},
{
"id": 130000,
"name": "河北省"
},
...
]
返回值 | 类型 | 是否必传 | 说明 |
---|---|---|---|
id | int | 是 | 省份id |
name | str | 是 | 省份名称 |
2)请求城市或区县数据
请求方式: GET /areas/(?P<pk>\d+)/
请求参数: 路径参数
参数 | 类型 | 是否必传 | 说明 |
---|---|---|---|
pk | int | 是 | 上级区划id(省份id用于获取城市数据,或城市id用于获取区县数据) |
返回数据: JSON
返回值 | 类型 | 是否必传 | 说明 |
---|---|---|---|
id | int | 是 | 上级区划id(省份id或城市id) |
name | str | 是 | 上级区划的名称 |
subs | list[] | 是 | 下属所有区划信息 |
如:
{
"id": "110100",
"name": "北京市",
"subs": [
{
"id": "110101",
"name": "东城区"
},
{
"id": "110102",
"name": "西城区"
}
]
}
在areas/serializers.py中新建序列化器
from rest_framework import serializers
from .models import Area
class AreaSerializer(serializers.ModelSerializer):
"""
行政区划信息序列化器
"""
class Meta:
model = Area
fields = ('id', 'name')
class SubAreaSerializer(serializers.ModelSerializer):
"""
子行政区划信息序列化器
"""
subs = AreaSerializer(many=True, read_only=True)
class Meta:
model = Area
fields = ('id', 'name', 'subs')
在areas/views.py中新建视图
from django.shortcuts import render
from rest_framework.viewsets import ReadOnlyModelViewSet
from .models import Area
from .serializers import AreaSerializer, SubAreaSerializer
# Create your views here.
class AreasViewSet(ReadOnlyModelViewSet):
"""
行政区划信息
"""
pagination_class = None # 区划信息不分页
def get_queryset(self):
"""
提供数据集
"""
if self.action == 'list':
return Area.objects.filter(parent=None)
else:
return Area.objects.all()
def get_serializer_class(self):
"""
提供序列化器
"""
if self.action == 'list':
return AreaSerializer
else:
return SubAreaSerializer
定义路由
router = DefaultRouter()
router.register(r'areas', views.AreasViewSet, base_name='areas')
urlpatterns = []
urlpatterns += router.urls