# 业务逻辑层(Service) 业务逻辑层是模块开发的第三步,也是最核心的部分。所有 CRUD 操作、业务规则、数据处理都封装在 Service 层的独立函数中。 ## 文件位置 ``` application/example/services.py ``` ## 命名规范 | 函数类型 | 命名格式 | 示例 | |:----|:----|:----| | 分页查询 | `get__page` | `get_example_page` | | 列表查询 | `get__list` | `get_example_list` | | 详情查询 | `get__detail` | `get_example_detail` | | 添加 | `add_` | `add_example` | | 更新 | `update_` | `update_example` | | 删除 | `delete_s` | `delete_examples` | | 状态更新 | `update__status` | `update_example_status` | | 数据列表 | `get__data` | `get_example_data` | ## 分页查询 ```python def get_example_page(request): """ 查询案例分页数据 Args: request: HttpRequest对象 - pageNo: 当前页码(可选,默认为1) - pageSize: 每页记录数(可选,默认为PAGE_SIZE) - name: 案例名称(可选,模糊查询) - type: 案例类型(可选,精确匹配) - status: 案例状态(可选,精确匹配) Returns: R: 包含分页数据的JSON响应 """ try: # 获取分页参数 page_no = int(request.GET.get('pageNo', 1)) page_size = int(request.GET.get('pageSize', PAGE_SIZE)) # 构建基础查询(只查询未删除的记录) query = Example.objects.filter(is_delete=False) # 应用筛选条件 query = _apply_filters(query, request) # 按排序字段升序排列 query = query.order_by("sort") # 执行分页查询 paginator = Paginator(query, page_size) try: page_list = paginator.page(page_no) except (PageNotAnInteger, InvalidPage, EmptyPage): page_list = paginator.page(1) page_no = 1 # 构建并返回分页数据 page_data = _build_page_data(page_list, paginator, page_no, page_size) return R.ok(data=page_data) except Exception as e: logging.error(f"查询案例分页数据异常: {str(e)}") return R.failed(msg="查询失败,请稍后重试") ``` ### 筛选条件应用 ```python def _apply_filters(queryset, request): """应用查询筛选条件(私有辅助函数)""" # 案例名称模糊筛选 name = request.GET.get('name') if name: queryset = queryset.filter(name__contains=name) # 案例类型筛选(精确匹配) type = request.GET.get('type') if type: queryset = queryset.filter(type=type) # 案例状态筛选(精确匹配) status = request.GET.get('status') if status: queryset = queryset.filter(status=status) return queryset ``` ### 分页数据构建 ```python def _build_page_data(page_list, paginator, page_no, page_size): """构建分页返回数据(私有辅助函数)""" records = [] for item in page_list: record = { 'id': item.id, 'name': item.name, 'avatar': get_file_url(item.avatar) if item.avatar else "", 'type': item.type, 'status': item.status, 'sort': item.sort, 'createUser': item.create_user, 'createTime': format_datetime(item.create_time), 'updateUser': item.update_user, 'updateTime': format_datetime(item.update_time), } records.append(record) return { 'records': records, 'total': paginator.count, 'size': page_size, 'current': page_no, 'pages': paginator.num_pages } ``` ### 分页响应格式 ```json { "code": 0, "data": { "records": [...], "total": 100, "size": 10, "current": 1, "pages": 10 }, "msg": "操作成功", "ok": true } ``` ## 详情查询 ```python def get_example_detail(id): """ 根据ID查询案例详情 Args: id: 案例ID Returns: dict/None: 案例详情字典,不存在时返回None """ try: instance = Example.objects.filter(is_delete=False, id=id).first() if not instance: return None return { 'id': instance.id, 'name': instance.name, 'avatar': get_file_url(instance.avatar) if instance.avatar else "", 'type': instance.type, 'status': instance.status, 'sort': instance.sort, } except Exception as e: logging.error(f"查询案例详情异常,ID: {id}, 错误: {str(e)}") return None ``` ## 添加记录 ```python def add_example(request): """ 添加案例 处理流程: 1. 解析请求体中的JSON数据 2. 表单验证 3. 处理头像图片(保存到 example 目录) 4. 创建数据库记录 """ # 解析请求参数 data, error = parse_request_body(request) if error: return R.failed(msg=error) # 表单验证 form = forms.ExampleForm(data) if not form.is_valid(): return R.failed(msg=regular.get_err(form)) try: cleaned_data = form.cleaned_data # 处理头像图片 avatar = cleaned_data.get('avatar') if avatar: avatar = save_file(avatar, "example") # 创建案例记录 Example.objects.create( name=cleaned_data.get('name'), avatar=avatar, type=cleaned_data.get('type'), status=cleaned_data.get('status'), sort=cleaned_data.get('sort'), create_user=get_username(request), update_user=get_username(request) ) return R.ok(msg="创建成功") except Exception as e: logging.error(f"添加案例异常: {str(e)}") return R.failed(msg="添加失败,请稍后重试") ``` ### 添加流程说明 ``` 请求 → parse_request_body → 表单验证 → 处理文件 → ORM.create → 返回结果 ``` | 步骤 | 函数 | 说明 | |:----|:----|:----| | 解析请求体 | `parse_request_body(request)` | 解析 JSON 请求体 | | 表单验证 | `forms.ExampleForm(data)` | 验证数据合法性 | | 处理文件 | `save_file(url, dir)` | 临时文件迁移到正式目录 | | 创建记录 | `Example.objects.create(...)` | ORM 创建数据库记录 | | 获取用户名 | `get_username(request)` | 从 JWT token 解析当前用户 | ## 更新记录 ```python def update_example(request): """ 更新案例 处理流程: 1. 解析请求体中的JSON数据 2. 验证案例ID 3. 表单验证 4. 查询现有记录 5. 处理头像图片(如有变化则保存新图片) 6. 更新各字段 7. 保存更新 """ # 解析请求参数 data, error = parse_request_body(request) if error: return R.failed(msg=error) # 验证案例ID instance_id = data.get('id') if not instance_id or not str(instance_id).isdigit() or int(instance_id) <= 0: return R.failed("案例ID无效") instance_id = int(instance_id) # 表单验证 form = forms.ExampleForm(data) if not form.is_valid(): return R.failed(msg=regular.get_err(form)) try: # 查询案例记录 instance = Example.objects.filter(id=instance_id, is_delete=False).first() if not instance: return R.failed("案例不存在") cleaned_data = form.cleaned_data # 处理头像图片(仅当有新图片且与当前不同时保存) avatar = cleaned_data.get('avatar') if avatar and avatar != instance.avatar: avatar = save_file(avatar, "example") else: avatar = instance.avatar # 更新各字段 instance.name = cleaned_data.get('name') instance.avatar = avatar instance.type = cleaned_data.get('type') instance.status = cleaned_data.get('status') instance.sort = cleaned_data.get('sort') instance.update_user = get_username(request) instance.save() return R.ok(msg="更新成功") except Exception as e: logging.error(f"更新案例异常,ID: {instance_id}, 错误: {str(e)}") return R.failed(msg="更新失败,请稍后重试") ``` ## 删除记录(批量) ```python def delete_examples(instance_ids): """ 删除案例(批量删除) 采用逻辑删除方式(is_delete=True),而非物理删除。 支持逗号分隔的多个ID。 Args: instance_ids: 案例ID字符串,多个ID用逗号分隔 例如: "1" 或 "1,2,3" """ if not instance_ids: return R.failed("记录ID不存在") try: # 解析ID列表 id_list = [int(id_str.strip()) for id_str in instance_ids.split(',') if id_str.strip()] if not id_list: return R.failed("无效的记录ID") # 批量更新删除标识(逻辑删除) updated_count = Example.objects.filter( id__in=id_list, is_delete=False ).update(is_delete=True) return R.ok(msg=f"本次共删除{updated_count}条数据") except ValueError: return R.failed("记录ID格式错误") except Exception as e: logging.error(f"删除案例异常,IDs: {instance_ids}, 错误: {str(e)}") return R.failed(msg="删除失败,请稍后重试") ``` ### 逻辑删除说明 项目采用逻辑删除(软删除),而非物理删除: ```python # 逻辑删除:设置 is_delete=True Example.objects.filter(id__in=id_list).update(is_delete=True) # 物理删除(不推荐):真正删除数据库记录 Example.objects.filter(id__in=id_list).delete() ``` 所有查询都必须加 `is_delete=False` 条件过滤已删除的数据。 ## 状态更新 ```python def update_example_status(request): """ 更新案例状态 单独更新案例的启用/禁用状态,不涉及其他字段。 """ # 解析请求参数 data, error = parse_request_body(request) if error: return R.failed(msg=error) # 验证案例ID instance_id = data.get('id') if not instance_id or not str(instance_id).isdigit() or int(instance_id) <= 0: return R.failed("案例ID无效") instance_id = int(instance_id) # 验证状态值(1=启用, 2=禁用) status = data.get('status') if status is None: return R.failed("状态值不能为空") try: status = int(status) if status not in [1, 2]: return R.failed("状态值无效") except ValueError: return R.failed("状态值格式错误") try: instance = Example.objects.filter(id=instance_id, is_delete=False).first() if not instance: return R.failed("案例不存在") instance.status = status instance.update_user = get_username(request) instance.save() return R.ok(msg="状态更新成功") except Exception as e: logging.error(f"更新案例状态异常,ID: {instance_id}, 错误: {str(e)}") return R.failed(msg="状态更新失败,请稍后重试") ``` ## 数据列表(下拉选择) ```python def get_example_data(): """ 获取所有启用的案例列表 通常用于前端下拉选择框等场景。 只返回 status=1(启用)且未删除的记录。 """ try: queryset = Example.objects.filter( is_delete=False, status=1 ).order_by("sort").values() return list(queryset) except Exception as e: logging.error(f"获取案例列表异常: {str(e)}") return [] ``` ## 常用工具函数 | 函数 | 来源 | 用途 | |:----|:----|:----| | `parse_request_body(request)` | `utils/common.py` | 解析 JSON 请求体 | | `regular.get_err(form)` | `utils/regular.py` | 提取表单错误信息 | | `get_username(request)` | `utils/security.py` | 从 JWT 获取当前用户名 | | `get_file_url(path)` | `utils/common.py` | 拼接文件完整 URL | | `save_file(url, dir)` | `utils/common.py` | 保存文件到正式目录 | | `format_datetime(dt)` | `utils/common.py` | 格式化日期时间 | | `R.ok()` / `R.failed()` | `utils/R.py` | 统一响应格式 | ## 开发要点 1. **所有查询都要加 `is_delete=False`**:过滤已删除的数据 2. **使用 `parse_request_body()` 解析请求体**:统一的 JSON 解析方式 3. **表单验证失败时使用 `regular.get_err()` 提取错误**:统一的错误信息格式 4. **使用 `get_username(request)` 获取当前用户**:从 JWT token 解析 5. **文件处理使用 `save_file()`**:临时文件迁移到正式目录 6. **批量删除支持逗号分隔的多个 ID**:如 "1,2,3" 7. **所有异常都要捕获并记录日志**:使用 `logging.error()` ## 总结 Service 层封装所有业务逻辑,每个 CRUD 操作都是独立的函数。使用 `parse_request_body` 解析请求体,`forms.ModelForm` 验证数据,`R.ok()` / `R.failed()` 返回统一响应。所有查询都必须加 `is_delete=False` 过滤已删除数据,批量删除采用逻辑删除方式。