DRF对省市区的选取操作
本篇博客主要讲解的是,在选中一个省份的时候,如何将后面的市自动调整为选中省份所属的市,同理,区县也一样
本文主要分七个模块:
1、数据库的表
2、html的设置
3、js的设置,主要为加载事件以及信息的提取
4、url模块
5、model的设置
6、Serializer的设置
7、view功能的实现
1、数据库表
这里我所用的只有一张表,省市区都在上面,上图为表的字段,具体形式如下:
我所采用的是自关联的方法,来获取上下级的省市区
2、html的设置
这就是省市区在html页面中的设置,采用表的结构设置,并且设置了失焦事件,这是调整的主要事件。
3、Js模块
js模块中,我先利用入口函数,从数据库提取出所有的省份,并且填入省份所在的select标签,利用的是字符串拼接的方式,填入id为province的value中。
$(function () {
username = localStorage.username
$('#username').text(username)
$.ajax({
url:'http://127.0.0.1:8000/areas/address/',
method:'GET',
contentType :'application/json',
dataType:'json',
success:function (data) {
var len_pro=data.length;
console.log(len_pro)
var str1='<option value="1">省</option>'
for(i=0;i<len_pro;i++){
console.log(typeof (data[i]['atitle']));
str1+='<option value="'+data[i]['id']+'">'+data[i]['atitle']+'</option>'
};
console.log(str1)
$('#province').html(str1)
},
error:function (data) {
alert('请求失败')
}
})
})
接下来的市的选择是建立在省级上的,因此,我在省份的按键上设置了一个失焦事件,在失去焦点之后,提取省份的内容,利用表的自关联区寻找该省份下的市(该功能我是通过前端js提取省份id,再通过拼接url将省份的id传到后端再进到数据库获取对应数据)
对于区也是如此获取,在这里就不详细讲解了。
4、url模块
这里我使用的是DRF中的DefaultRouter包,通过不同的请求方式,从而自动生成不同的路径,在这里我主要使用的是get请求。
5、model的设置
class Address(models.Model):
atitle = models.CharField(max_length=50,verbose_name='区域名字')
#这个pid字段是自关联字段,‘self’是关联自己,‘null=True’是该字段允许为空的意思,‘related_name='subs'’相当于重命名了,别的请求来访问就是通过该名字
pid = models.ForeignKey('self',on_delete=models.SET_NULL,null=True,related_name='subs',blank=True,verbose_name='父级id')
class Meta:
db_table = 'sh_address'
verbose_name = '行政区域'
verbose_name_plural = verbose_name
#在前端显示atitle
def __str__(self):
return self.atitle
这是表模型。
on_delete字段的设置:
CASCADE:这就是默认的选项,级联删除,你无需显性指定它。
PROTECT: 保护模式,如果采用该选项,删除的时候,会抛出ProtectedError错误。
SET_NULL: 置空模式,删除的时候,外键字段被设置为空,前提就是blank=True, null=True,定义该字段的时候,允许为空。
SET_DEFAULT: 置默认值,删除的时候,外键字段设置为默认值,所以定义外键的时候注意加上一个默认值。
**SET()?*自定义一个值,该值当然只能是对应的实体了
注:
null 是针对数据库而言,如果 null=True, 表示数据库的该字段可以为空,即在Null字段显示为YES。
blank 是针对表单的,如果 blank=True,表示你的表单填写该字段的时候可以不填,但是对数据库来说,没有任何影响
6、Serializer的设置
class ProvinceSerializer(serializers.ModelSerializer):
class Meta:
model=models.Address
fields = ['id','atitle']
class CityAreaSerializer(serializers.ModelSerializer):
subs = ProvinceSerializer(many=True,read_only=True)
class Meta:
model=models.Address
fields = ['id','atitle','subs']
这里设置了两个序列化器,第一个是处理省份的,第二个是处理市与区的。
注:
- model 指明参照哪个模型类
- fields 指明为模型类的哪些字段生成
- 可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段
7、view功能的实现
class AreaView(ReadOnlyModelViewSet,CacheResponseMixin):
pagination_class = None
def get_serializer_class(self):
if self.action == 'list':
return serializers.ProvinceSerializer
else:
return serializers.CityAreaSerializer
def get_queryset(self):
if self.action== 'list':
return Address.objects.filter(pid=None)
else:
return Address.objects.all()
action就是后面的name,如果后面是list,就是省份的请求,如果是detail,就是市区的请求。
因为省份的请求是没有上级id的,市区有,所以需要我们从前端传递id过来。