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

 

posted @ 2021-12-22 12:02  linuxTang  阅读(195)  评论(0)    收藏  举报