在用戶錄入地址時,需要進行省市區的選擇。在頁面加載時,向后端請求省份數據,當用戶選擇確定省份后,向后端請求該省份的城市數據;在用戶選擇確定城市數據后,向后端請求該城市的區縣信息。我們把這個過程稱為省市區三級聯動。
我們新建一個應用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