:::tip 城市管理 城市管理模块用于管理行政区划数据,支持省/市/区/街道/社区五级行政区划。通过 `parent_code` 字段实现树形结构。 ::: ## 城市模型 ```python # 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) ``` :::tip 行政区划与用户关联 用户表通过 `province_code`、`city_code`、`district_code`、`street_code` 四个字段关联城市表的 `area_code`,`city_info` 字段存储拼接后的城市名称(如"广东省深圳市南山区")。 ::: ## API 接口 | 接口 | 方法 | 权限节点 | 说明 | |------|------|---------|------| | `/city/list` | GET | `sys:city:list` | 城市列表(支持按 pid 和 name 筛选) | | `/city/detail/` | GET | `sys:city:detail` | 城市详情 | | `/city/add` | POST | `sys:city:add` | 新增城市 | | `/city/update` | POST | `sys:city:update` | 编辑城市 | | `/city/delete/` | POST | `sys:city:delete` | 删除城市(支持批量) | ## 列表查询 ``` GET /city/list?pid=0&name=深圳 ``` ### 查询参数 | 参数 | 类型 | 说明 | |------|------|------| | `pid` | int | 上级城市 ID(默认 0,查顶级) | | `name` | str | 城市名称(模糊查询,不区分大小写) | ### 响应示例 ```json { "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 } ``` ## 子级城市查询 根据上级城市编码获取子级城市列表,用于前端级联选择器: ```python # 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) ``` ## 添加城市 ```python # 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="创建成功") ``` ## 删除城市(带子级校验) 删除城市前会检查是否存在子级城市,如果有则阻止删除: ```python 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}条数据") ``` :::warning 删除规则 城市采用**自下而上**的删除策略:必须先删除最底层的社区/街道,再删除区县,最后删除城市和省份。这保证了数据的完整性。 ::: ## 前端级联选择 前端使用 `el-cascader` 组件实现省市区三级联动选择: ```vue ``` ## 数据导入 行政区划数据通常通过 SQL 文件批量导入,而非手动添加。项目内置了全国行政区划数据: ```bash # 导入行政区划数据(首次部署时执行) python manage.py migrate ``` :::tip 数据来源 行政区划数据来源于国家统计局公开数据,覆盖全国省/市/区/街道/社区五级行政区划。数据量约 70 万条记录。 ::: ## 总结 城市管理模块具备以下特点: ``` 1. 五级行政区划:省/市/区/街道/社区,通过 parent_code 形成树形结构 2. 丰富字段:含经纬度、拼音、邮编等信息 3. 用户关联:用户表通过四级编码关联城市表 4. 级联选择:前端通过 el-cascader 组件实现级联选择 5. 删除校验:删除前检查子级,保证数据完整性 6. 批量导入:内置全国行政区划数据 ```