Skip to content

Service 层

Service 层是业务逻辑层,负责实现具体的业务规则。简单 CRUD 模块继承 BaseService 基类,只需声明差异点即可获得完整的增删改查能力。

文件位置

src/modules/position/service.py

完整代码

python
# +======================================================================
# | 模块: 岗位业务服务层
# | 说明: 继承 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()

代码解析

必须声明的差异点

python
repo_cls = PositionRepository  # 关联的 Repository 类(不是实例)
model = Position               # 关联的模型类

注意

repo_cls类属性,值为 Repository (不是实例)。BaseService.__init__ 会自动实例化它。

分页查询配置

python
page_like_fields = ('name',)          # 模糊查询字段(LIKE)
page_eq_fields = ('status',)          # 精确查询字段(=)
page_order_by = (('sort', 'asc'),)    # 排序规则

当调用 get_page(handler) 时,基类自动:

  1. handler 的查询参数读取 pageNopageSize
  2. page_like_fields 中的字段执行 LIKE %keyword% 查询
  3. page_eq_fields 中的字段执行精确匹配
  4. page_order_by 排序
  5. 返回分页数据

唯一性校验

python
unique_fields = {'name': '岗位名称不能重复'}

字典的 key 是模型字段名,value 是校验失败时的错误提示。在 add()update() 时,基类自动查询数据库判断是否重复。

生命周期钩子

python
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 对象

开发要点

  1. 必须声明 repo_clsmodel:基类所有方法依赖这两个属性
  2. repo_cls 是类而非实例:传入 Repository 类,基类自动实例化
  3. 分页配置按需声明page_like_fields / page_eq_fields / page_order_by
  4. 唯一性校验通过 unique_fields 配置:基类自动处理,无需手写查询
  5. 删除前校验用 _before_delete 钩子:返回错误字符串中止操作
  6. 必须创建模块级单例xxx_service = XxxService()
  7. 所有方法接收 handler(Tornado Handler 实例):非 request 对象

总结

Service 层继承 BaseService 获得通用 CRUD 能力,只需声明差异点(repo_cls/model/page_like_fields/unique_fields/serialize_maps)并覆写钩子方法。必须创建模块级单例,所有方法接收 Tornado Handler 实例。

小蚂蚁云团队 · 提供技术支持