5.4 KiB
5.4 KiB
Service 层
Service 层是业务逻辑层,负责实现具体的业务规则。简单 CRUD 模块继承 BaseService 基类,只需声明差异点即可获得完整的增删改查能力。
文件位置
src/modules/position/service.py
完整代码
# +======================================================================
# | 模块: 岗位业务服务层
# | 说明: 继承 BaseService 获得通用 CRUD,声明差异点 + 覆盖删除前钩子
# +======================================================================
"""岗位业务服务。"""
from typing import Optional
from common.utils.helpers import parse_id_list
from core.base_service import BaseService
from modules.position.models import Position
from modules.position.repository import PositionRepository
from modules.user.models import User
from modules.user.repository import UserRepository
class PositionService(BaseService(Position]):
"""岗位业务服务类,继承基础服务获得通用 CRUD 能力。"""
# ============================================================
# 数据访问与模型
# ============================================================
repo_cls = PositionRepository
model = Position
# ============================================================
# 分页差异点
# ============================================================
page_like_fields = ('name',)
page_eq_fields = ('status',)
page_order_by = (('sort', 'asc'),)
# ============================================================
# 唯一性校验
# ============================================================
unique_fields = {'name': '岗位名称不能重复'}
# ============================================================
# 删除前校验
# ============================================================
def _before_delete(self, ids) -> Optional[str]:
"""删除前校验:存在用户引用该岗位时禁止删除。"""
id_list = parse_id_list(str(ids))
if id_list:
user_repo = UserRepository()
if user_repo.filter(User.position_id.in_(id_list), User.is_delete == 0).first():
return "存在用户引用该岗位,请先调整用户岗位"
return None
# 模块级单例
position_service = PositionService()
代码解析
必须声明的差异点
repo_cls = PositionRepository # 关联的 Repository 类(不是实例)
model = Position # 关联的模型类
:::tip 注意
repo_cls 是 类属性,值为 Repository 类(不是实例)。BaseService.__init__ 会自动实例化它。
:::
分页查询配置
page_like_fields = ('name',) # 模糊查询字段(LIKE)
page_eq_fields = ('status',) # 精确查询字段(=)
page_order_by = (('sort', 'asc'),) # 排序规则
当调用 get_page(handler) 时,基类自动:
- 从
handler的查询参数读取pageNo、pageSize - 对
page_like_fields中的字段执行LIKE %keyword%查询 - 对
page_eq_fields中的字段执行精确匹配 - 按
page_order_by排序 - 返回分页数据
唯一性校验
unique_fields = {'name': '岗位名称不能重复'}
字典的 key 是模型字段名,value 是校验失败时的错误提示。在 add() 和 update() 时,基类自动查询数据库判断是否重复。
生命周期钩子
def _before_delete(self, ids) -> Optional[str]:
BaseService 提供以下钩子方法,子类可按需覆盖:
| 钩子 | 触发时机 | 返回值 |
|---|---|---|
_before_delete(ids) |
删除操作前 | 返回错误字符串则中止删除,返回 None 则继续 |
_before_add(handler, data) |
新增操作前 | 可修改 data(原地修改) |
_before_update(handler, data) |
更新操作前 | 可修改 data(原地修改) |
_serialize(item) |
列表序列化时 | 自定义返回字段 |
_serialize_detail(obj) |
详情序列化时 | 自定义返回字段 |
基类提供的通用方法
| 方法 | 说明 |
|---|---|
get_page(handler) |
分页查询,返回 R 对象 |
get_detail(obj_id) |
查询详情,返回序列化字典或 None |
add(handler) |
新增记录,返回 R 对象 |
update(handler) |
更新记录,返回 R 对象 |
delete(handler, ids) |
单条/批量删除(软删除),返回 R 对象 |
batch_delete(handler) |
批量删除(请求体为 ID 数组),返回 R 对象 |
update_status(handler) |
更新状态,返回 R 对象 |
get_options(handler) |
下拉列表查询,返回 R 对象 |
开发要点
- 必须声明
repo_cls和model:基类所有方法依赖这两个属性 repo_cls是类而非实例:传入 Repository 类,基类自动实例化- 分页配置按需声明:
page_like_fields/page_eq_fields/page_order_by - 唯一性校验通过
unique_fields配置:基类自动处理,无需手写查询 - 删除前校验用
_before_delete钩子:返回错误字符串中止操作 - 必须创建模块级单例:
xxx_service = XxxService() - 所有方法接收
handler(Tornado Handler 实例):非 request 对象
总结
Service 层继承 BaseService 获得通用 CRUD 能力,只需声明差异点(repo_cls/model/page_like_fields/unique_fields/serialize_maps)并覆写钩子方法。必须创建模块级单例,所有方法接收 Tornado Handler 实例。