Django 自关联之 - 地址省市区
创建一个新的模块应用areas
指令:
python ../../manage.py startapp areas
在配置文件,添加路径:
INSTALLED_APPS = [
'areas.apps.AreasConfig',
]
在 models.py 文件创建数据表:
from django.db import models
# Create your models here.
class Areas(models.Model):
name = models.CharField(max_length=50, verbose_name='地名')
pid = models.ForeignKey('self', on_delete=models.SET_NULL, related_name='addinfo', null=True, blank=True, verbose_name='上一级别的行政区的id')
# on_delete = models.CASCADE # 删除关联数据的时候,与之相关联的也删除
# on_delete = models.DO_NOTHING # ... , 什么操作也不做
# on_delete = models.PROTECT # ... ,引发报错
# on_delete = models.SET_NULL # ... ,设置为空
# on_delete = models.SET_DEFAULT # ... , 设置为默认值
# on_delete = models.SET # ... , 删除关联数据
class Meta:
db_table = 'areas'
def __str__(self):
return self.name
说明:
- name 是省市区的名字
- pid 外键,self 自相关,这里也可以使用Areas。
- related_name=’addinfo’ ,相当于一对多的类型,子表的名字,可以通过areas.addinfo.all() 来获取子表的所有信息。
- null 为True表示可为空,因为省级行政单位没有父级
- blank 为True 表示在admin后台调试数据库的时候可以允许为空
迁移数据库
每当对models模型进行修改时,都要记得迁移数据库
python manage.py makemigrations
python manage.py migrate
然后下载数据库文件areas.sql ,然后在文件对应的路径导入到数据库中
mysql -uroot -p shanghui < areas.sql
areas.sql 部分内容:
新建一个serializers.py文件写序列化器类
from rest_framework import serializers
from . import models
# 这个序列化器就是展示地区名
class AreaInfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.Areas
fields = ('id', 'name',)
# 这个序列器展示他的下一级地区名
class NextAreaInfoSerializer(serializers.ModelSerializer):
# 嵌套关系
addinfo = AreaInfoSerializer(many=True, read_only=True)
# 注意 这里的 addinfo 要和 上面 models.py 文件里的related_name 名字相对应
# addinfo = serializers.StringRelatedField(many=True, read_only=True)
# 这个是返回字符串显示的是__str__方法返回的内容。
# 上面什么都不写,也就是只有下面Meta类的时候,默认是PrimaryKeyrelatedField,也就是显示id
# 显示下一级的内容
class Meta:
model = models.Areas
fields = ('id', 'name', 'addinfo', )
在 views.py 文件编写:
这里使用ReadOnlyModelViewSet,因为能根据不同的请求指定不同的序列化器
from django.shortcuts import render
from rest_framework.viewsets import ReadOnlyModelViewSet
from . import models
from . import serializers
# Create your views here.
class AreasView(ReadOnlyModelViewSet):
def get_queryset(self):
if self.action == 'list':
# pid = None 的时候,返回的是省级数据
return models.Areas.objects.filter(pid=None)
else:
return models.Areas.objects.all()
def get_serializer_class(self):
if self.action == 'list':
return serializers.AreaInfoSerializer
else:
return serializers.NextAreaInfoSerializer
在urls文件配置路由器
在使用viewsets类的时候,一般都是使用路由器自动配置路径
from django.conf.urls import url
from rest_framework import routers
from . import views
router = routers.DefaultRouter()# 默认附带一个api根式图,相对于SimpleRouter()来说
# router = routers.SimpleRouter()
router.register(r'areas', views.AreasView, base_name='areas')
urlpatterns = [
]
urlpatterns += router.urls
通过接口文档查看效果
前端js文件代码:
主要使用到的是jQuery 里面的change事件。
// 地址 省 下拉菜单
$.ajax({
url:'http://127.0.0.1:8000/areas/areas',
type:'GET',
dataType:'json',
contentType: 'application/json',
success:function (data) {
console.log(data.length);
var newdata = '<option value="1">' + '省' + '</option>';
for(var i=0;i<data.length;i++){
newdata += '<option value =' + data[i]["id"] + '>' + data[i]['name'] + '</option>'
}
$('#addprovince').html(newdata);
},
error:function (data) {
console.log(data);
}
});
// 地址 市 下拉菜单
$('#addprovince').change(function () {
var data_id = $(this).val();
$.ajax({
url:'http://127.0.0.1:8000/areas/areas/'+ data_id + '/',
type:'GET',
success:function (data) {
var city_data = '';
for(var i=0;i<data['addinfo'].length; i++) {
// console.log(data['addinfo'][i]);
city_data += '<option value =' + data['addinfo'][i]["id"] + '>' + data['addinfo'][i]['name'] + '</option>'
}
$('#addcity').html(city_data);
var city_length = $('#addcity').children().length;
// console.log('个数',city_length);
if (city_length ==1){
// var district = '<option value="3">' + '/' + '</option>';
var district = $('#addcity').html();
$('#adddistrict').html(district);
}
},
error:function (data) {
console.log(data);
}
})
});
// 地址 区 下拉菜单
$('#addcity').change(function () {
var data_id = $(this).val();
$.ajax({
url:'http://127.0.0.1:8000/areas/areas/'+ data_id + '/',
type:'GET',
success:function (data) {
// console.log(data);
var district_data = '';
for(var i=0;i<data['addinfo'].length; i++) {
// console.log(data['addinfo'][i]);
district_data += '<option value =' + data['addinfo'][i]["id"] + '>' + data['addinfo'][i]['name'] + '</option>'
}
$('#adddistrict').html(district_data);
},
error:function (data) {
console.log(data);
}
})
});