Become a sponsor

行政区划
行政区划模块管理全国省/市/区/街道四级区域数据,支持树形结构查询、级联选择器、拼音自动生成等功能。用户表通过 province_code/city_code/district_code/street_code 四个字段关联城市表的 area_code。
src/modules/city/
├── models.py # 城市模型
├── schema.py # 表单验证(WTForms)
├── repository.py # 数据访问层
├── service.py # 业务逻辑层(继承 BaseService)
└── router.py # 路由控制器# src/modules/city/models.py
class City(BaseModel, BaseDB):
"""
城市区域模型
支持省、市、县区、街道四级区域结构。
"""
__tablename__ = DB_PREFIX + "city"
__table_comment__ = "城市表"
# 城市区号
city_code = db.Column(db.String(6), nullable=False, index=True, comment="城市区号")
# 行政编码(用于用户表关联)
area_code = db.Column(db.String(20), nullable=False, index=True, comment="行政编码")
# 上级行政编码
parent_code = db.Column(db.String(20), nullable=False, index=True, comment="上级行政编码")
# 邮政编码
zip_code = db.Column(db.String(6), nullable=False, comment="邮政编码")
# 城市级别:0-省份 1-城市 2-县区 3-街道 4-社区
level = db.Column(db.Integer, default=0, server_default=text('0'), index=True,
comment="城市级别:0-省份 1-城市 2-县区 3-街道 4-社区")
# 上级城市ID
pid = db.Column(db.Integer, default=0, server_default=text('0'), index=True, comment="上级城市ID")
# 城市名称
name = db.Column(db.String(150), nullable=False, comment="城市名称")
# 城市简称
short_name = db.Column(db.String(150), nullable=False, index=True, comment="城市简称")
# 城市全称(沿 pid 链拼接,如"台湾省,云林,元长,华鹿")
full_name = db.Column(db.String(150), nullable=True, comment="城市全称")
# 城市拼音(由简称自动生成,如"TaiWan")
pinyin = db.Column(db.String(150), nullable=True, comment="城市拼音")
# 经纬度
lng = db.Column(db.String(150), nullable=True, comment="城市经度")
lat = db.Column(db.String(150), nullable=True, comment="城市纬度")城市服务继承 BaseService,并通过钩子实现自动派生字段:
# src/modules/city/service.py
class CityService(BaseService):
repository = CityRepository
form = CityForm
model_name = "城市"
@classmethod
def before_add(cls, form):
"""新增前钩子:自动补全 full_name / pinyin"""
data = form.data
return {
"full_name": cls._build_full_name(data.get("pid") or 0, data.get("name")),
"pinyin": cls._build_pinyin(data.get("shortName") or data.get("name")),
}
@classmethod
def before_delete(cls, ids):
"""删除前校验:检查是否存在子级城市"""
for cid in ids:
if CityRepository.count_children(cid, parent_field='pid') > 0:
raise BizError(f"城市ID {cid} 存在子级城市,请先删除子级城市")
@classmethod
def _detail_dict(cls, obj):
"""详情序列化:追加 parentName(父级城市名称)"""
data = model_to_dict(obj)
parent_id = getattr(obj, 'pid', None)
if parent_id:
parent = CityRepository.get_by_id(parent_id)
data['parentName'] = parent.name if parent else None
else:
data['parentName'] = None
return data| 字段 | 生成规则 | 示例 |
|---|---|---|
full_name | 沿 pid 链向上拼接,逗号分隔 | 台湾省,云林,元长,华鹿 |
pinyin | 由简称生成无音调拼音,每音节首字母大写 | TaiWan、HuaLu |
城市采用树形结构(pid 字段),删除前检查是否存在子级城市:
广东省 (pid=0)
├── 深圳市 (pid=广东省.id)
│ ├── 南山区 (pid=深圳市.id)
│ └── 福田区 (pid=深圳市.id)
└── 广州市 (pid=广东省.id)删除「深圳市」前,会检查其下是否存在「南山区」「福田区」等子级城市。
城市模块提供树形数据接口,用于前端级联选择器:
def get_city_tree():
"""获取城市树形数据,构建省-市-区三级树形结构"""
all_cities = CityRepository.list_all()
city_dicts = models_to_list(all_cities)
return _build_city_tree(city_dicts)
def _build_city_tree(city_list, parent_id=0):
"""递归构建城市树形结构"""
tree = []
for city in city_list:
if city.get("pid") == parent_id:
node = {
"id": city.get("id"),
"name": city.get("name"),
"code": city.get("area_code"),
"level": city.get("level"),
"children": _build_city_tree(city_list, city.get("id")),
}
if not node["children"]:
del node["children"]
tree.append(node)
return tree用户表通过四个字段关联城市表:
# src/modules/system/user/models.py
class User(BaseModel, BaseDB):
# 省份编码
province_code = db.Column(db.String(30), nullable=False, comment="省份编码")
# 城市编码
city_code = db.Column(db.String(30), nullable=False, comment="城市编码")
# 县区编码
district_code = db.Column(db.String(30), nullable=False, comment="县区编码")
# 街道编码
street_code = db.Column(db.String(30), nullable=False, comment="街道编码")
# 省市区信息(拼接后的可读文本,如"广东省深圳市南山区")
city_info = db.Column(db.String(255), nullable=True, comment="省市区信息")用户新增/更新时,前端通过级联选择器传入 [省编码, 市编码, 区编码, 街道编码] 数组,Service 层拆分到独立字段:
# src/modules/system/user/service.py
def _apply_city(create_data, city):
"""将行政区划数组拆分到对应的字段"""
create_data["province_code"] = city[0]
create_data["city_code"] = city[1]
create_data["district_code"] = city[2]
create_data["street_code"] = city[3]| 方法 | 路径 | 权限节点 | 说明 |
|---|---|---|---|
| GET | /api/v1/city/list | sys:city:list | 城市列表(支持 pid/name 筛选) |
| GET | /api/v1/city/detail/<id> | sys:city:detail | 城市详情 |
| GET | /api/v1/city/child/<code> | - | 子级城市列表(级联选择器用) |
| GET | /api/v1/city/tree | - | 城市树形数据 |
| POST | /api/v1/city/add | sys:city:add | 新增城市 |
| PUT | /api/v1/city/update | sys:city:update | 编辑城市 |
| DELETE | /api/v1/city/delete/<id> | sys:city:delete | 删除城市 |
| 字典编码 | 用途 | 字典项示例 |
|---|---|---|
city_level | 城市级别名称 | 0=省份, 1=城市, 2=县区, 3=街道, 4=社区 |
行政区划模块采用树形结构(pid 字段),支持省/市/区/街道四级管理。before_add 钩子自动补全 full_name(沿 pid 链拼接)和 pinyin(由简称生成),before_delete 钩子校验子级城市引用。用户表通过 area_code 字段关联城市表,前端使用级联选择器。