diango完成省市区三级联动
一分析:
1先欣赏一下自关联的表:
ID name parent_id 110000 北京市 110100 北京市 110000 110101 东城区 110100 110102 西城区 110100 110103 朝阳区 110100 120000 河北省 120100 沧州市 120000 120101 肃宁县 120100 120102 南皮县 120100
自关联表查询口诀:
查顶级数据用parent__isnull=True,查子级数据需要先查询父级然后再查询子级
解释:
1查河北省,河南省,北京市等这些顶级,所谓顶级就是parent_id=Null的字段:
Area.objects.filter(parent__isnull=True)
2查沧州市,石家庄市,北京市这些父级市
parent_model = Area.objects.get(id=parent_id)
3查沧州市下面的县或者北京市下面的区:
parent_model.subs.all()
2欣赏一下我们打算组装的json数据表:
省份数据结构:
{ 'code':200, 'province_list':[ {'id':110000,'name':'北京市'}, {'id':120000,'name':'天津市'}, ] }
市或区县数据结构:
{ 'code':200, 'sub_data':{ 'id':110000,'name':'北京市', 'subs':[ {'id':110100,'name':'北京市'}, {'id':110101,'name':'东城区'}, ] } }
3分析从数据库取值后如何组装身份数据结构:
省份数据:
#我要要的最终效果 { 'code':200, 'province_list':[ {'id':110000,'name':'北京市'}, {'id':120000,'name':'天津市'}, ] }
#骨架是这个样子的 { 'code':200, 'province_list':[{},{},{}] }
province_model_list = Area.objects.filter(parent__isnull=True) #我们可以先定义一个空列表 province_list=[] #我们每遍历一条数据就组装一个字典 for province_model in province_model_list: province_dict={ 'id':province_model.id, 'name':province_model.name } #最后把字典追加到列表里就组成了[{},{},{}] province_list.append(province_dict) #最后我们把数据返给前端 return JsonResponse({'code':200,'province_list':province_list})
4分析一下上面实现省份数据的过程:
1我们采用剥洋葱原理先分析数据结构: { #这个是return时,返给前端的状态码,我们不用管 'code':200, #这个需要我们补充的内容时一个大列表[],列表内是{每一个城市的id和name}, 'province_list':[{'id':110000,'name':'北京市'},{'id':120000,'name':'天津市'}, ] } 2那现在的问题就是我们要怎么拿到这些数据,怎么组装成这种结构[{},{}]? 我们可以先定义一个空列表[ ],然后从数据库查出每个省份的地址,每遍历一条数据就组装一个{},然后append到列表里,就能最终组成这样的效果:[{'id':110000,'name':'北京市'},{'id':120000,'name':'天津市'}, ] 最后我们用JsonResponse直接把组好的数据结构传给前端,就可以啦!
5接下来我们开始组装区县数据:
{ 'code':200, 'sub_data':{ #父级 'id':110000,'name':'北京市', #区县级 'subs':[ {'id':110100,'name':'北京市'}, {'id':110101,'name':'东城区'}, ] } }
分析:
也就是说要想把区县级数据查出来,首先需要查出父级,因为顶级没有parent_id,而父级parent_id指向的是顶级的id,根据这一特点,我们先把父级的数据获取到,然后用django一对多的特有查询方法公式取出数据
备注:subs是我们定义模型类时的related_name='subs'
#获取浏览器传过来的id area_id = request.GET.get('area_id') #根据获取的id查出父级数据 parent_model = Area.objects.get(id=area_id) #用一对多的方法通过父级查出子级数据 sub_model_list = parent_model.subs.all()
我们先从里往外剥洋葱
{ 'code':200, 'sub_data':{ #父级 'id':110000,'name':'北京市', #区县级 'subs':[{},{},] } }
1完成'subs':[{},{},]
#1先列表里的字典遍历出来 subs = [] for sub_model in sub_model_list: sub_dict={'id':sub_model.id,'name':sub_model.name} #2然后把遍历的每一个字典都添加到列表中得到[{},{},] subs.append(sub_dict)
2完成:'sub_data':{}
因为我们前面已经获得了父级元素:parent_model = Area.objects.get(id=area_id)
所以此时我们直接组装就行:
sub_data = { 'id':parent_model.id, 'name':parent_model.name, 'subs':[{},{}] }
又因为[{},{}]我们在第一步已经组装好了,所以:
sub_data = { 'id':parent_model.id, 'name':parent_model.name, 'subs':subs }
最后我们把数据返给前端:
return JsonResponse({'code':200,'sub_data':sub_data})
二开始
1创建项目:
D:\PycharmProjects>django-admin startproject laiyue_2022
2创建应用:
D:\PycharmProjects\laiyue_2022>python manage.py startapp threeLevelLinkage
3添加应用:
INSTALLED_APPS = [ 'threeLevelLinkage', ]
4创建模板:
class Area(models.Model):
name = models.CharField(max_length=20,verbose_name='名称')
#自关联外键
#on_delete=models.SET_NULL因为是自关联,如果我们要删除子级或父级,我们只需要把自关联的这个parentID设为null就可以了
#related_name='subs'当我们要给表建立关系的时候,有一个关联名称,重命名一对多的关联字段名称
parent = models.ForeignKey('self',on_delete=models.CASCADE,related_name='subs',blank=True,verbose_name='上级行政区划')
class Meta:
db_table = 'tb_areas'
verbose_name = '省市区'
verbose_name_plural = '省市区'
def __str__(self):
return self.name
5同步数据库:
D:\PycharmProjects\laiyue_2022>python manage.py makemigrations
D:\PycharmProjects\laiyue_2022>python manage.py migrate
6编写视图逻辑:
from django.http import JsonResponse from django.views import View from .models import Area #省市区数据 class AreasView(View): def get(self,request): area_id = request.GET.get('area_id') #查省 if not area_id: try: #查省份数据(属性名__条件表达式=值:将所有可以为空的值的数据全部找出来) province_model_list = Area.objects.filter(parent__isnull=True) #序列化省份数据 province_list = [] for province_model in province_model_list: province_dict = { 'id':province_model.id, 'name':province_model.name } province_list.append(province_dict) return JsonResponse({'code':200,'province_list':province_list}) except Exception as e: result = {'code':201,'error':'查询省份数据失败'} return JsonResponse(result) #查市区县 else: try: #把省的id赋值给parent_id,查询出父级(如果id是省就查省的数据,如果是市就查市的数据) parent_model = Area.objects.get(id=area_id) #一查多的语法:模型类对象.小写模型类名_set #sub_model_list = parent_model.area_set.all() #查询parent_model下面的城市 sub_model_list = parent_model.subs.all() subs = [] #拼接数据 for sub_model in sub_model_list: sub_dict = { 'id':sub_model.id, 'name':sub_model.name } subs.append(sub_dict) sub_data ={ 'id':parent_model.id, 'name':parent_model.name, #'subs':[{},{}] 'subs':subs } return JsonResponse({'code':200,'sub_data':sub_data}) except Exception as e: result = {'code':202,'error':'查询省下面的数据失败'} return JsonResponse(result)
7配置主路由:
urlpatterns = [ path('admin/', admin.site.urls), path('v1/parentment/',include('threeLevelLinkage.urls')), ]
8配置子路由:
from django.urls import path from . import views urlpatterns = [ #省市区三级联动 path('areas',views.AreasView.as_view()), ]
9浏览器访问测试:
http://127.0.0.1:8000/v1/address/areas?area_id=120100
http://127.0.0.1:8000/v1/address/areas