Files
djangoadmin-wiki/DjangoAdmin_Flask_NaiveVue/zh/volume7/router.md
T
2026-09-13 23:01:19 +08:00

9.0 KiB
Raw Blame History

Router层规范

概述

Router 层是 HTTP 接口层,负责定义路由、权限装饰器和请求参数解析。每个业务模块对应一个 router 文件,所有业务逻辑委托给 Service 层处理。

:::tip 设计原则

  • Router 层不含业务逻辑,仅做路由定义、权限校验和参数解析
  • 装饰器顺序固定为:路由 → 权限 → 演示模式 → 操作日志
  • Service 模块在文件顶部统一导入(from src.modules.system.position import service as position)
  • Router 负责调用 R.ok() / R.failed() 封装响应,Service 不返回 R 对象 :::

完整示例

以岗位模块为例,以下为 src/modules/system/position/router.py 的核心代码(省略版权头):

"""
岗位管理控制器模块
=============================================================

提供岗位(Position)相关的API接口,包括:
- 岗位分页查询
- 岗位详情查询
- 岗位添加、更新、删除
- 岗位状态设置
- 岗位数据列表获取
"""
from flask import Blueprint, request

from src.middleware import check_demo, operation_log
from src.core.permission import check_permission
from src.modules.system.position import service as position
from src.common.utils.request import parse_batch_ids, parse_request_body

from src.core import response as R

position_blue = Blueprint('position', __name__, url_prefix='/position')


# ============================================================
# 岗位分页查询
# ============================================================

@position_blue.route('/page', methods=["GET"])
@check_permission("sys:position:page")
@operation_log("岗位管理", "查询")
def page():
    """查询岗位分页数据"""
    return R.ok(data=position.get_position_page(request.args))


# ============================================================
# 岗位详情查询
# ============================================================

@position_blue.route('/detail/<int:id>', methods=["GET"])
@check_permission("sys:position:detail")
@operation_log("岗位管理", "详情")
def detail(id):
    """查询岗位详情"""
    data = position.get_position_detail(id)
    return R.ok(data=data)


# ============================================================
# 岗位添加
# ============================================================

@position_blue.route('/add', methods=["POST"])
@check_permission("sys:position:add")
@check_demo
@operation_log("岗位管理", "新增")
def add():
    """添加岗位"""
    json_data, err = parse_request_body()
    if err:
        return R.failed(msg=err)
    position.add_position(json_data)
    return R.ok(msg="添加成功")


# ============================================================
# 岗位更新
# ============================================================

@position_blue.route('/update', methods=["PUT"])
@check_permission("sys:position:update")
@check_demo
@operation_log("岗位管理", "修改")
def update():
    """更新岗位"""
    json_data, err = parse_request_body()
    if err:
        return R.failed(msg=err)
    position.update_position(json_data)
    return R.ok(msg="更新成功")


# ============================================================
# 岗位删除
# ============================================================

@position_blue.route('/delete/<string:id>', methods=["DELETE"])
@check_permission("sys:position:delete")
@check_demo
@operation_log("岗位管理", "删除")
def delete(id):
    """删除岗位(支持逗号分隔的多个ID)"""
    count = position.delete_positions(id)
    return R.ok(msg=f"本次共删除{count}条数据")


# ============================================================
# 岗位批量删除
# ============================================================

@position_blue.route('/batchDelete', methods=["DELETE"])
@check_permission("sys:position:batchDelete")
@check_demo
@operation_log("岗位管理", "批量删除")
def batch_delete():
    """批量删除岗位"""
    id_str, err = parse_batch_ids()
    if err:
        return err
    count = position.delete_positions(id_str)
    return R.ok(msg=f"本次共删除{count}条数据")


# ============================================================
# 岗位状态设置
# ============================================================

@position_blue.route('/status', methods=["PUT"])
@check_permission("sys:position:status")
@check_demo
@operation_log("岗位管理", "状态变更")
def status():
    """设置岗位状态"""
    json_data, err = parse_request_body()
    if err:
        return R.failed(msg=err)
    position.update_position_status(json_data)
    return R.ok(msg="设置成功")


# ============================================================
# 岗位列表获取(无分页)
# ============================================================

@position_blue.route('/list', methods=["GET"])
@check_permission("sys:position:list")
@operation_log("岗位管理", "查询")
def get_position_list():
    """获取岗位数据列表(无分页,用于下拉选择)"""
    result = position.get_position_list(request.args)
    return R.ok(data=result)

装饰器说明

装饰器 作用 适用场景
@position_blue.route() 定义 HTTP 方法和路径 所有接口
@check_permission('sys:position:page') RBAC 权限校验 所有接口
@check_demo 演示模式拦截(禁止写操作) 写操作(add/update/delete/status/batchDelete)
@operation_log("岗位管理", "查询") 操作日志自动记录 所有接口

装饰器顺序必须严格遵守:路由 → 权限 → 演示模式 → 操作日志。

导入规范

# 模块顶部统一导入
from src.middleware import check_demo, operation_log
from src.core.permission import check_permission
from src.modules.system.position import service as position
from src.common.utils.request import parse_batch_ids, parse_request_body
from src.core import response as R
导入项 来源 说明
check_demo src.middleware 演示模式装饰器
operation_log src.middleware 操作日志装饰器
check_permission src.core.permission 权限校验装饰器
service as position 业务模块 Service 层代理函数
parse_request_body src.common.utils.request 解析请求体 JSON
parse_batch_ids src.common.utils.request 解析批量删除的 ID 数组
R src.core 统一响应封装

请求参数解析

# 解析请求体(返回元组:数据, 错误信息)
json_data, err = parse_request_body()
if err:
    return R.failed(msg=err)

# 解析批量删除的ID数组(返回元组:ID字符串, 错误信息)
id_str, err = parse_batch_ids()
if err:
    return err
函数 作用 返回值
parse_request_body() 从请求体解析 JSON (dict, None) 或 (None, error_msg)
parse_batch_ids() 从请求体解析 ID 数组 (id_str, None) 或 (None, R.failed(...))

响应封装

Router 层负责调用 R.ok() / R.failed() 封装响应:

# 查询类:Service 返回数据,Router 用 R.ok(data=...) 包装
return R.ok(data=position.get_position_page(request.args))

# 写操作类:Service 执行成功后无返回值,Router 返回成功消息
position.add_position(json_data)
return R.ok(msg="添加成功")

# 删除类:Service 返回删除数量,Router 格式化消息
count = position.delete_positions(id)
return R.ok(msg=f"本次共删除{count}条数据")

:::warning Service 不返回 R 对象 Service 层入参为数据字典、出参为纯数据(或 None),业务失败通过 raise BizError 表达。Router 层负责封装 R.ok() / R.failed() 响应。 :::

权限字符串命名规范

sys:{module}:{action}
动作 HTTP 方法 说明
page GET 分页查询
detail GET 详情查询
list GET 列表查询
add POST 新增
update PUT 更新
delete DELETE 单条删除
batchDelete DELETE 批量删除
status PUT 状态变更

模块注册

在 src/routes/v1.py 中注册模块:

from src.modules.system.position.router import position_blue

BLUEPRINTS = [
    # ... 其他模块
    position_blue,
    # ... 其他模块
]

开发要点

  1. Router 层不含业务逻辑:仅做路由定义、权限校验和参数解析
  2. 装饰器顺序:路由 → 权限 → 演示模式 → 操作日志
  3. Service 模块顶部统一导入:from src.modules.system.position import service as position
  4. 使用 parse_request_body() 解析请求体:返回 (data, err) 元组
  5. 使用 parse_batch_ids() 解析批量操作的 ID 数组
  6. Router 负责封装响应:Service 不返回 R 对象

总结

Router 层是 HTTP 请求的入口,负责路由定义、权限校验和参数解析,不含业务逻辑。装饰器顺序固定为路由 → 权限 → 演示模式 → 操作日志。Service 模块在文件顶部统一导入,Router 负责调用 R.ok() / R.failed() 封装响应,Service 不返回 R 对象。