Become a sponsor

城市管理
城市管理模块用于管理行政区划数据,支持省/市/区/街道/社区五级行政区划。通过 parent_code 字段实现树形结构。
# application/city/models.py
from application.models import BaseModel
class City(BaseModel):
"""城市/行政区划模型类"""
class Meta:
db_table = 'django_city'
city_code = models.CharField(max_length=6, verbose_name='城市区号')
area_code = models.CharField(max_length=20, verbose_name='行政编码')
parent_code = models.CharField(max_length=20, null=True, blank=True, verbose_name='上级行政编码')
zip_code = models.CharField(max_length=6, verbose_name='邮政编码')
level = models.IntegerField(default=0, verbose_name='城市级别:0-省份 1-城市 2-县区 3-街道 4-社区')
pid = models.IntegerField(default=0, verbose_name='上级城市ID')
name = models.CharField(max_length=150, verbose_name='城市名称')
short_name = models.CharField(max_length=150, verbose_name='城市简称')
full_name = models.CharField(max_length=150, null=True, blank=True, verbose_name='城市全称')
pinyin = models.CharField(max_length=150, null=True, blank=True, verbose_name='城市拼音')
lng = models.CharField(max_length=150, null=True, blank=True, verbose_name='城市经度')
lat = models.CharField(max_length=150, null=True, blank=True, verbose_name='城市纬度')| 字段 | 说明 | 示例 |
|---|---|---|
city_code | 城市区号 | 0755 |
area_code | 行政编码(唯一标识) | 440305 |
parent_code | 上级行政编码 | 440300(深圳市) |
zip_code | 邮政编码 | 518000 |
level | 层级:0-省 1-市 2-区 3-街道 4-社区 | 2 |
pid | 上级城市 ID(关联本表 id) | 123 |
name | 城市名称 | 南山区 |
short_name | 城市简称 | 南山 |
full_name | 城市全称 | 广东省深圳市南山区 |
pinyin | 城市拼音 | nanshanqu |
lng | 经度 | 113.9304 |
lat | 纬度 | 22.5333 |
城市通过 parent_code 和 pid 两个字段形成五级行政区划树形结构:
中国 (parent_code=null, level=0)
+-- 广东省 (parent_code=100000, level=0)
| +-- 深圳市 (parent_code=440000, level=1)
| | +-- 南山区 (parent_code=440300, level=2)
| | | +-- 粤海街道 (parent_code=440305, level=3)
| | +-- 福田区 (parent_code=440300, level=2)
| +-- 广州市 (parent_code=440000, level=1)
+-- 浙江省 (parent_code=100000, level=0)
+-- 杭州市 (parent_code=330000, level=1)行政区划与用户关联
用户表通过 province_code、city_code、district_code、street_code 四个字段关联城市表的 area_code,city_info 字段存储拼接后的城市名称(如"广东省深圳市南山区")。
| 接口 | 方法 | 权限节点 | 说明 |
|---|---|---|---|
/city/list | GET | sys:city:list | 城市列表(支持按 pid 和 name 筛选) |
/city/detail/<int:city_id> | GET | sys:city:detail | 城市详情 |
/city/add | POST | sys:city:add | 新增城市 |
/city/update | POST | sys:city:update | 编辑城市 |
/city/delete/<int:city_ids> | POST | sys:city:delete | 删除城市(支持批量) |
GET /city/list?pid=0&name=深圳| 参数 | 类型 | 说明 |
|---|---|---|
pid | int | 上级城市 ID(默认 0,查顶级) |
name | str | 城市名称(模糊查询,不区分大小写) |
{
"code": 0,
"data": [
{
"id": 1,
"cityCode": "0755",
"areaCode": "440305",
"parentCode": "440300",
"zipCode": "518057",
"level": 2,
"pid": 123,
"name": "南山区",
"shortName": "南山",
"fullName": "广东省深圳市南山区",
"pinyin": "nanshanqu",
"lng": "113.9304",
"lat": "22.5333"
}
],
"msg": "操作成功",
"ok": true
}根据上级城市编码获取子级城市列表,用于前端级联选择器:
# application/city/services.py
def get_child_cities(city_code):
"""根据上级城市编码获取子级城市列表"""
child_list = City.objects.filter(
is_delete=False,
parent_code=city_code
).values()
return list(child_list)# application/city/services.py
def add_city(request):
"""添加城市"""
data, error = parse_request_body(request)
if error:
return R.failed(msg=error)
# 表单验证
form = forms.CityForm(data)
if not form.is_valid():
return R.failed(msg=regular.get_err(form))
cleaned_data = form.cleaned_data
City.objects.create(
city_code=cleaned_data.get('cityCode'),
area_code=cleaned_data.get('areaCode'),
parent_code=cleaned_data.get('parentCode'),
zip_code=cleaned_data.get('zipCode'),
level=int(cleaned_data.get('level')),
pid=int(cleaned_data.get('pid')),
name=cleaned_data.get('name'),
short_name=cleaned_data.get('shortName'),
lng=cleaned_data.get('lng'),
lat=cleaned_data.get('lat'),
create_user=get_username(request),
update_user=get_username(request)
)
return R.ok(msg="创建成功")删除城市前会检查是否存在子级城市,如果有则阻止删除:
def delete_cities(city_ids):
"""删除城市(批量删除)"""
id_list = [int(id_str.strip()) for id_str in city_ids.split(',') if id_str.strip()]
# 检查是否有子级城市
has_children = City.objects.filter(pid__in=id_list, is_delete=False).exists()
if has_children:
return R.failed("请先删除子级城市")
# 批量逻辑删除
updated_count = City.objects.filter(
id__in=id_list, is_delete=False
).update(is_delete=True)
return R.ok(msg=f"本次共删除{updated_count}条数据")删除规则
城市采用自下而上的删除策略:必须先删除最底层的社区/街道,再删除区县,最后删除城市和省份。这保证了数据的完整性。
前端使用 el-cascader 组件实现省市区三级联动选择:
<el-cascader
v-model="selectedRegion"
:props="cascaderProps"
placeholder="请选择省/市/区"
/>
<script setup>
const cascaderProps = {
lazy: true,
lazyLoad: async (node, resolve) => {
const { level, value } = node;
const res = await getCityList({ pid: value || 0 });
const nodes = res.map(item => ({
value: item.areaCode,
label: item.name,
leaf: level >= 2 // 区县级为叶子节点
}));
resolve(nodes);
}
};
</script>行政区划数据通常通过 SQL 文件批量导入,而非手动添加。项目内置了全国行政区划数据:
# 导入行政区划数据(首次部署时执行)
python manage.py migrate数据来源
行政区划数据来源于国家统计局公开数据,覆盖全国省/市/区/街道/社区五级行政区划。数据量约 70 万条记录。
城市管理模块具备以下特点:
1. 五级行政区划:省/市/区/街道/社区,通过 parent_code 形成树形结构
2. 丰富字段:含经纬度、拼音、邮编等信息
3. 用户关联:用户表通过四级编码关联城市表
4. 级联选择:前端通过 el-cascader 组件实现级联选择
5. 删除校验:删除前检查子级,保证数据完整性
6. 批量导入:内置全国行政区划数据