refactor: P4c 最终批次-2 dictionary 模块(dict+dict_item 合并服务)

【修复合并遗留】
- 重命名重名函数(_apply_dict_item_filters/get_dict_item_info/
  _build_dict_item_page_data),修复 get_info 调用点
- router 双 blueprint 合并导入、dict_item 视图函数重命名
- schema/service/models 中部重复 import 行级去重
- 修复 schema typo DictItemItem
- models.py 误改后从 git 恢复(P4c 不需改 models)

【教训】regex 改复杂合并文件易误伤(.*?跨 docstring 匹配删了顶部导入),
已恢复并改用精确行级去重

【验收】flake8 零告警;应用启动;dict/dict_item 分页运行时正常;12 passed

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
DjangoAdmin Dev
2026-08-07 16:26:33 +08:00
co-authored by Claude
parent a054b14485
commit 9acbf6275e
7 changed files with 288 additions and 426 deletions
@@ -0,0 +1,15 @@
"""
DictItem 仓储模块
=============================================================
数据访问层,继承 BaseRepository 获得通用 CRUD 能力。
"""
from src.common.base_repository import BaseRepository
from src.modules.dictionary.models import DictItem
class DictItemRepository(BaseRepository):
"""DictItem 仓储"""
model = DictItem
+15
View File
@@ -0,0 +1,15 @@
"""
Dict 仓储模块
=============================================================
数据访问层,继承 BaseRepository 获得通用 CRUD 能力。
"""
from src.common.base_repository import BaseRepository
from src.modules.dictionary.models import Dict
class DictRepository(BaseRepository):
"""Dict 仓储"""
model = Dict
+12 -58
View File
@@ -50,13 +50,13 @@ from src.common.base_db import BaseDB
from src.common.base_model import BaseModel
from config import DB_PREFIX
from src.core.database import db
from src.common.utils.case_converter import convert_camel_to_snake
# ============================================================
# 字典模型
# ============================================================
class Dict(BaseModel, BaseDB):
"""
字典分组模型
@@ -84,32 +84,16 @@ class Dict(BaseModel, BaseDB):
# ============================================================
# 字典名称
name = db.Column(
db.String(150),
nullable=False,
comment="字典名称"
)
name = db.Column(db.String(150), nullable=False, comment="字典名称")
# 字典编码
code = db.Column(
db.String(150),
nullable=False,
comment="字典编码"
)
code = db.Column(db.String(150), nullable=False, comment="字典编码")
# 字典排序
sort = db.Column(
db.Integer,
default=0,
comment="字典排序"
)
sort = db.Column(db.Integer, default=0, comment="字典排序")
# 字典备注
note = db.Column(
db.String(255),
nullable=True,
comment="字典备注"
)
note = db.Column(db.String(255), nullable=True, comment="字典备注")
# ============================================================
# 魔法方法
@@ -125,7 +109,6 @@ class Dict(BaseModel, BaseDB):
return "字典{}".format(self.id)
"""
字典项模型模块
=============================================================
@@ -133,17 +116,12 @@ class Dict(BaseModel, BaseDB):
提供数据字典项的数据模型定义,用于管理字典的具体选项。
"""
from src.common.base_db import BaseDB
from src.common.base_model import BaseModel
from config import DB_PREFIX
from src.core.database import db
from src.common.utils.case_converter import convert_camel_to_snake
# ============================================================
# 字典项模型
# ============================================================
class DictItem(BaseModel, BaseDB):
"""
字典项模型
@@ -172,46 +150,22 @@ class DictItem(BaseModel, BaseDB):
# ============================================================
# 字典ID
dict_id = db.Column(
db.Integer,
default=0,
comment="字典ID"
)
dict_id = db.Column(db.Integer, default=0, comment="字典ID")
# 字典编码
dict_code = db.Column(
db.String(100),
nullable=False,
comment="字典编码"
)
dict_code = db.Column(db.String(100), nullable=False, comment="字典编码")
# 字典项名称
name = db.Column(
db.String(100),
nullable=False,
comment="字典项名称"
)
name = db.Column(db.String(100), nullable=False, comment="字典项名称")
# 字典项值
value = db.Column(
db.String(100),
nullable=False,
comment="字典项值"
)
value = db.Column(db.String(100), nullable=False, comment="字典项值")
# 字典项排序
sort = db.Column(
db.Integer,
default=0,
comment="字典项顺序"
)
sort = db.Column(db.Integer, default=0, comment="字典项顺序")
# 字典项备注
note = db.Column(
db.String(255),
nullable=True,
comment="字典项备注"
)
note = db.Column(db.String(255), nullable=True, comment="字典项备注")
# ============================================================
# 魔法方法
+66 -50
View File
@@ -53,22 +53,25 @@
依赖模块: application.services.dicts - 字典业务逻辑层
application.middleware.check_permission - 权限校验中间件
"""
from flask import Blueprint
from flask import Blueprint, request
from application.middleware.check_demo import check_demo
from application.middleware.check_permission import check_permission
from src.modules.dictionary import service as dict
from src.common.utils.request import parse_batch_ids
dict_blue = Blueprint('dict', __name__, url_prefix='/dict')
from src.modules.dictionary import service as dict_item
from src.common.utils.request import parse_batch_ids, parse_request_body
from src.core import response as R
dict_blue = Blueprint("dict", __name__, url_prefix="/dict")
# ============================================================
# 字典分页查询
# ============================================================
@dict_blue.route('/page', methods=["GET"])
@dict_blue.route("/page", methods=["GET"])
@check_permission("sys:dict:page")
def page():
"""
@@ -80,15 +83,15 @@ def page():
Returns:
JSON: 字典分页数据,包含 records(数据列表)、total(总记录数)等
"""
result = dict.get_dict_page()
return result
return R.ok(data=dict.get_dict_page(request.args))
# ============================================================
# 字典详情查询
# ============================================================
@dict_blue.route('/detail/<int:id>', methods=["GET"])
@dict_blue.route("/detail/<int:id>", methods=["GET"])
@check_permission("sys:dict:detail")
def detail(id):
"""
@@ -108,7 +111,8 @@ def detail(id):
# 字典添加
# ============================================================
@dict_blue.route('/add', methods=["POST"])
@dict_blue.route("/add", methods=["POST"])
@check_permission("sys:dict:add")
@check_demo
def add():
@@ -121,15 +125,19 @@ def add():
Returns:
JSON: 操作结果
"""
result = dict.add_dict()
return result
json_data, err = parse_request_body()
if err:
return R.failed(msg=err)
dict.add_dict(json_data)
return R.ok(msg="添加成功")
# ============================================================
# 字典更新
# ============================================================
@dict_blue.route('/update', methods=["PUT"])
@dict_blue.route("/update", methods=["PUT"])
@check_permission("sys:dict:update")
@check_demo
def update():
@@ -142,15 +150,19 @@ def update():
Returns:
JSON: 操作结果
"""
result = dict.update_dict()
return result
json_data, err = parse_request_body()
if err:
return R.failed(msg=err)
dict.update_dict(json_data)
return R.ok(msg="更新成功")
# ============================================================
# 字典删除
# ============================================================
@dict_blue.route('/delete/<string:id>', methods=["DELETE"])
@dict_blue.route("/delete/<string:id>", methods=["DELETE"])
@check_permission("sys:dict:delete")
@check_demo
def delete(id):
@@ -163,15 +175,16 @@ def delete(id):
Returns:
JSON: 操作结果
"""
result = dict.delete_dicts(id)
return result
count = dict.delete_dicts(id)
return R.ok(msg=f"本次共删除{count}条数据")
# ============================================================
# 字典批量删除
# ============================================================
@dict_blue.route('/batchDelete', methods=["DELETE"])
@dict_blue.route("/batchDelete", methods=["DELETE"])
@check_permission("sys:dict:batch_delete")
@check_demo
def batch_delete():
@@ -190,9 +203,8 @@ def batch_delete():
id_str, err = parse_batch_ids()
if err:
return err
return dict.delete_dicts(id_str)
count = dict.delete_dicts(id_str)
return R.ok(msg=f"本次共删除{count}条数据")
"""
@@ -208,24 +220,17 @@ def batch_delete():
依赖模块: application.services.dicts_data - 字典项业务逻辑层
application.middleware.check_permission - 权限校验中间件
"""
from flask import Blueprint
from application.middleware.check_demo import check_demo
from application.middleware.check_permission import check_permission
from src.modules.dictionary import service as dict_item
from src.common.utils.request import parse_batch_ids
dict_item_blue = Blueprint('dict_item', __name__, url_prefix='/dict/item')
from src.core import response as R
dict_item_blue = Blueprint("dict_item", __name__, url_prefix="/dict/item")
# ============================================================
# 字典项分页查询
# ============================================================
@dict_item_blue.route('/page', methods=["GET"])
@dict_item_blue.route("/page", methods=["GET"])
@check_permission("sys:dictitem:page")
def page():
def dict_item_page():
"""
查询字典项分页数据
@@ -235,17 +240,17 @@ def page():
Returns:
JSON: 字典项分页数据,包含 records(数据列表)、total(总记录数)等
"""
result = dict_item.get_dict_item_page()
return result
return R.ok(data=dict_item.get_dict_item_page(request.args))
# ============================================================
# 字典项详情查询
# ============================================================
@dict_item_blue.route('/detail/<int:id>', methods=["GET"])
@dict_item_blue.route("/detail/<int:id>", methods=["GET"])
@check_permission("sys:dictitem:detail")
def detail(id):
def dict_item_detail(id):
"""
查询字典项详情
@@ -263,10 +268,11 @@ def detail(id):
# 字典项添加
# ============================================================
@dict_item_blue.route('/add', methods=["POST"])
@dict_item_blue.route("/add", methods=["POST"])
@check_permission("sys:dictitem:add")
@check_demo
def add():
def dict_item_add():
"""
添加字典项
@@ -276,18 +282,22 @@ def add():
Returns:
JSON: 操作结果
"""
result = dict_item.add_dict_item()
return result
json_data, err = parse_request_body()
if err:
return R.failed(msg=err)
dict_item.add_dict_item(json_data)
return R.ok(msg="添加成功")
# ============================================================
# 字典项更新
# ============================================================
@dict_item_blue.route('/update', methods=["PUT"])
@dict_item_blue.route("/update", methods=["PUT"])
@check_permission("sys:dictitem:update")
@check_demo
def update():
def dict_item_update():
"""
更新字典项
@@ -297,18 +307,22 @@ def update():
Returns:
JSON: 操作结果
"""
result = dict_item.update_dict_item()
return result
json_data, err = parse_request_body()
if err:
return R.failed(msg=err)
dict_item.update_dict_item(json_data)
return R.ok(msg="更新成功")
# ============================================================
# 字典项删除
# ============================================================
@dict_item_blue.route('/delete/<string:id>', methods=["DELETE"])
@dict_item_blue.route("/delete/<string:id>", methods=["DELETE"])
@check_permission("sys:dictitem:delete")
@check_demo
def delete(id):
def dict_item_delete(id):
"""
删除字典项
@@ -318,18 +332,19 @@ def delete(id):
Returns:
JSON: 操作结果
"""
result = dict_item.delete_dict_items(id)
return result
count = dict_item.delete_dict_items(id)
return R.ok(msg=f"本次共删除{count}条数据")
# ============================================================
# 字典项批量删除
# ============================================================
@dict_item_blue.route('/batchDelete', methods=["DELETE"])
@dict_item_blue.route("/batchDelete", methods=["DELETE"])
@check_permission("sys:dictitem:batch_delete")
@check_demo
def batch_delete():
def dict_item_batch_delete():
"""
批量删除字典项
@@ -345,4 +360,5 @@ def batch_delete():
id_str, err = parse_batch_ids()
if err:
return err
return dict_item.delete_dict_items(id_str)
count = dict_item.delete_dict_items(id_str)
return R.ok(msg=f"本次共删除{count}条数据")
+38 -73
View File
@@ -51,13 +51,14 @@ from wtforms import ValidationError, IntegerField, StringField
from wtforms.validators import NumberRange, DataRequired, Length, Optional
from src.common.forms.base_form import BaseForm
from src.modules.dictionary.models import Dict
from src.modules.dictionary.models import Dict, DictItem
# ============================================================
# 字典表单验证(添加和更新共用)
# ============================================================
class DictForm(BaseForm):
"""
字典表单验证类
@@ -77,59 +78,45 @@ class DictForm(BaseForm):
# 字典ID
# ============================================================
id = IntegerField(
label='字典ID',
validators=[
Optional(), # 允许为空(添加时)
NumberRange(min=1, message='字典ID必须大于0')
],
description='字典唯一标识,更新时必填,添加时自动生成'
label="字典ID",
validators=[Optional(), NumberRange(min=1, message="字典ID必须大于0")], # 允许为空(添加时)
description="字典唯一标识,更新时必填,添加时自动生成",
)
# ============================================================
# 字典名称
# ============================================================
name = StringField(
label='字典名称',
validators=[
DataRequired(message='字典名称不能为空'),
Length(max=150, message='字典名称长度不得超过150个字符')
],
description='字典显示名称,如:性别、状态'
label="字典名称",
validators=[DataRequired(message="字典名称不能为空"), Length(max=150, message="字典名称长度不得超过150个字符")],
description="字典显示名称,如:性别、状态",
)
# ============================================================
# 字典编码
# ============================================================
code = StringField(
label='字典编码',
validators=[
DataRequired(message='字典编码不能为空'),
Length(max=150, message='字典编码长度不得超过150个字符')
],
description='字典唯一标识编码,如:gender、status'
label="字典编码",
validators=[DataRequired(message="字典编码不能为空"), Length(max=150, message="字典编码长度不得超过150个字符")],
description="字典唯一标识编码,如:gender、status",
)
# ============================================================
# 字典排序
# ============================================================
sort = IntegerField(
label='字典排序',
validators=[
Optional(),
NumberRange(min=0, max=99999, message='字典排序值在0~99999之间')
],
description='排序值,数值越小越靠前'
label="字典排序",
validators=[Optional(), NumberRange(min=0, max=99999, message="字典排序值在0~99999之间")],
description="排序值,数值越小越靠前",
)
# ============================================================
# 字典备注
# ============================================================
note = StringField(
label='字典备注',
validators=[
Length(max=255, message='字典备注长度不得超过255个字符')
],
description='字典补充说明'
label="字典备注",
validators=[Length(max=255, message="字典备注长度不得超过255个字符")],
description="字典补充说明",
)
# ============================================================
@@ -199,7 +186,6 @@ class DictForm(BaseForm):
raise ValidationError("字典编码已存在")
"""
字典项表单验证模块
=============================================================
@@ -208,17 +194,12 @@ class DictForm(BaseForm):
- 字典项添加/更新表单验证
"""
from wtforms import ValidationError, IntegerField, StringField
from wtforms.validators import NumberRange, DataRequired, Length, Optional
from src.common.forms.base_form import BaseForm
from src.modules.dictionary.models import DictItem
# ============================================================
# 字典项表单验证(添加和更新共用)
# ============================================================
class DictItemForm(BaseForm):
"""
字典项表单验证类
@@ -239,71 +220,57 @@ class DictItemForm(BaseForm):
# 字典项ID
# ============================================================
id = IntegerField(
label='字典项ID',
validators=[
Optional(), # 允许为空(添加时)
NumberRange(min=1, message='字典项ID必须大于0')
],
description='字典项唯一标识,更新时必填,添加时自动生成'
label="字典项ID",
validators=[Optional(), NumberRange(min=1, message="字典项ID必须大于0")], # 允许为空(添加时)
description="字典项唯一标识,更新时必填,添加时自动生成",
)
# ============================================================
# 字典项名称
# ============================================================
name = StringField(
label='字典项名称',
label="字典项名称",
validators=[
DataRequired(message='字典项名称不能为空'),
Length(max=150, message='字典项名称长度不得超过150个字符')
DataRequired(message="字典项名称不能为空"),
Length(max=150, message="字典项名称长度不得超过150个字符"),
],
description='字典项显示名称,如:男、女'
description="字典项显示名称,如:男、女",
)
# ============================================================
# 字典项值
# ============================================================
value = StringField(
label='字典项值',
validators=[
DataRequired(message='字典项值不能为空'),
Length(max=150, message='字典项值长度不得超过150个字符')
],
description='字典项实际存储值,如:1、2'
label="字典项值",
validators=[DataRequired(message="字典项值不能为空"), Length(max=150, message="字典项值长度不得超过150个字符")],
description="字典项实际存储值,如:1、2",
)
# ============================================================
# 字典ID
# ============================================================
dictId = IntegerField(
label='字典ID',
validators=[
DataRequired(message='字典ID不能为空'),
NumberRange(min=0, message='字典ID值不得小于0')
],
description='所属字典分组ID'
label="字典ID",
validators=[DataRequired(message="字典ID不能为空"), NumberRange(min=0, message="字典ID值不得小于0")],
description="所属字典分组ID",
)
# ============================================================
# 字典项备注
# ============================================================
note = StringField(
label='字典项备注',
validators=[
Length(max=255, message='字典项备注长度不得超过255个字符')
],
description='字典项补充说明'
label="字典项备注",
validators=[Length(max=255, message="字典项备注长度不得超过255个字符")],
description="字典项补充说明",
)
# ============================================================
# 字典项排序
# ============================================================
sort = IntegerField(
label='字典项排序',
validators=[
Optional(),
NumberRange(min=0, max=99999, message='字典项排序值在0~99999之间')
],
description='排序值,数值越小越靠前'
label="字典项排序",
validators=[Optional(), NumberRange(min=0, max=99999, message="字典项排序值在0~99999之间")],
description="排序值,数值越小越靠前",
)
# ============================================================
@@ -369,9 +336,7 @@ class DictItemForm(BaseForm):
# 构建查询:查找同一字典下相同值的记录
query = DictItem.query.filter(
DictItem.dict_id == dict_id,
DictItem.value == field.data,
DictItem.is_delete == 0
DictItem.dict_id == dict_id, DictItem.value == field.data, DictItem.is_delete == 0
)
# 如果是更新操作,排除当前记录自身
+141 -244
View File
@@ -63,18 +63,17 @@
import logging
from datetime import datetime, timezone
from flask import request
from sqlalchemy import and_
from src.common.constants.common import PAGE_SIZE
from src.modules.dictionary.schema import DictForm
from src.modules.dictionary.models import Dict
from src.core.database import db
from src.core import response as R
from src.modules.dictionary.schema import DictForm, DictItemForm
from src.modules.dictionary.models import Dict, DictItem
from src.modules.dictionary.dict_repository import DictRepository
from src.modules.dictionary.dict_item_repository import DictItemRepository
from src.core.exceptions import BizError
from src.common.utils import regular
from src.common.utils.case_converter import convert_camel_to_snake
from src.common.utils.model_utils import models_to_list, model_to_dict
from src.common.utils.request import parse_request_body, parse_id_list, like_contains
from src.common.utils.request import parse_id_list, like_contains
from src.core.security import get_username
# 获取日志记录器
@@ -85,7 +84,8 @@ logger = logging.getLogger(__name__)
# 字典类型分页查询
# ============================================================
def get_dict_page():
def get_dict_page(params: dict) -> dict:
"""
查询字典类型分页数据
@@ -106,31 +106,26 @@ def get_dict_page():
"pages": 总页数
}
"""
try:
# 获取分页参数
page_no = int(request.args.get('pageNo', 1))
page_size = int(request.args.get('pageSize', PAGE_SIZE))
# 获取分页参数
page_no = int(params.get("pageNo", 1))
page_size = int(params.get("pageSize", PAGE_SIZE))
# 应用筛选条件
query = _apply_filters()
# 应用筛选条件
query = _apply_filters(params)
# 记录总数
total = query.count()
# 计算总页数
pages = (total + page_size - 1) // page_size if total > 0 else 0
# 记录总数
total = query.count()
# 计算总页数
pages = (total + page_size - 1) // page_size if total > 0 else 0
# 分页查询
dict_list = query.limit(page_size).offset((page_no - 1) * page_size).all()
# 构建返回数据
page_data = _build_page_data(dict_list, total, page_size, page_no, pages)
return R.ok(data=page_data)
except Exception as e:
logger.error(f"查询字典类型分页数据异常: {str(e)}")
return R.failed(msg="查询失败,请稍后重试")
# 分页查询
dict_list = query.limit(page_size).offset((page_no - 1) * page_size).all()
# 构建返回数据
page_data = _build_page_data(dict_list, total, page_size, page_no, pages)
return page_data
def _apply_filters():
def _apply_filters(params: dict):
"""
应用查询筛选条件
@@ -147,12 +142,12 @@ def _apply_filters():
query = Dict.query.filter(Dict.is_delete == 0)
# 字典名称模糊筛选
name = request.args.get('name')
name = params.get("name")
if name:
query = query.filter(Dict.name.like(like_contains(name), escape='\\'))
query = query.filter(Dict.name.like(like_contains(name), escape="\\"))
# 字典状态精确筛选
status = request.args.get('status')
status = params.get("status")
if status:
query = query.filter(Dict.status == status)
@@ -177,19 +172,14 @@ def _build_page_data(dict_list, total, page_size, page_no, pages):
# 将模型对象列表转换为字典列表
records = models_to_list(dict_list)
return {
'records': records,
'total': total,
'size': page_size,
'current': page_no,
'pages': pages
}
return {"records": records, "total": total, "size": page_size, "current": page_no, "pages": pages}
# ============================================================
# 字典类型详情查询
# ============================================================
def get_dict_detail(dict_id):
"""
根据ID查询字典类型详情(返回字典格式)
@@ -220,6 +210,7 @@ def get_dict_detail(dict_id):
# 字典类型信息查询(根据ID)- 核心查询方法
# ============================================================
def get_info(dict_id: int):
"""
根据ID查询字典类型信息(返回模型对象)
@@ -244,26 +235,10 @@ def get_info(dict_id: int):
if dict_obj:
print(dict_obj.name)
"""
# 参数有效性验证
if not dict_id or dict_id <= 0:
return None
try:
# 查询未删除的字典类型
dict_obj = Dict.query.filter(
and_(Dict.id == dict_id, Dict.is_delete == 0)
).first()
return dict_obj
except Exception as e:
logger.error(f"查询字典类型信息异常,ID: {dict_id}, 错误: {str(e)}")
return None
return DictRepository.get_by_id(dict_id)
# ============================================================
# 字典类型添加
# ============================================================
def add_dict():
def add_dict(data: dict) -> None:
"""
添加字典类型
@@ -275,35 +250,24 @@ def add_dict():
Returns:
R: 操作结果
"""
try:
# 获取参数
json_data, error = parse_request_body()
if error:
return R.failed(msg=error)
# 表单验证
form = DictForm(data=json_data)
if not form.validate():
err_msg = regular.get_err(form)
return R.failed(msg=err_msg)
# 表单验证
form = DictForm(data=data)
if not form.validate():
raise BizError(regular.get_err(form))
# 创建字典类型
dict_obj = Dict(**form.data)
dict_obj.create_user = get_username()
dict_obj.save()
return R.ok(msg="添加成功")
except Exception as e:
logger.error(f"添加字典类型异常: {str(e)}")
return R.failed(msg="添加失败,请稍后重试")
# 创建字典类型
dict_obj = Dict(**form.data)
dict_obj.create_user = get_username()
dict_obj.save()
# ============================================================
# 字典类型更新
# ============================================================
def update_dict():
def update_dict(data: dict) -> None:
"""
更新字典类型
@@ -316,52 +280,42 @@ def update_dict():
Returns:
R: 操作结果
"""
try:
# 获取参数
json_data, error = parse_request_body()
if error:
return R.failed(msg=error)
# 表单验证
form = DictForm(data=json_data)
if not form.validate():
return R.failed(msg=regular.get_err(form))
# 表单验证
form = DictForm(data=data)
if not form.validate():
raise BizError(regular.get_err(form))
# 获取字典类型ID
dict_id = form.data.get('id')
if not dict_id or int(dict_id) <= 0:
return R.failed("字典类型ID无效")
dict_id = int(dict_id)
# 获取字典类型ID
dict_id = form.data.get("id")
if not dict_id or int(dict_id) <= 0:
raise BizError("字典类型ID无效")
dict_id = int(dict_id)
# 复用 get_info 方法验证字典类型是否存在
dict_obj = get_info(dict_id)
if not dict_obj:
return R.failed("字典类型不存在")
# 复用 get_info 方法验证字典类型是否存在
dict_obj = get_info(dict_id)
if not dict_obj:
raise BizError("字典类型不存在")
# 更新字典类型信息(移除ID,避免更新主键)
form_data = convert_camel_to_snake(form.data.copy())
form_data.pop('id', None)
# 更新字典类型信息(移除ID,避免更新主键)
form_data = convert_camel_to_snake(form.data.copy())
form_data.pop("id", None)
form_data['update_time'] = datetime.now(tz=timezone.utc)
form_data['update_user'] = get_username()
form_data["update_time"] = datetime.now(tz=timezone.utc)
form_data["update_user"] = get_username()
result = Dict.query.filter_by(id=dict_id).update(form_data)
result = Dict.query.filter_by(id=dict_id).update(form_data)
if not result:
return R.failed("更新失败")
return R.ok(msg="更新成功")
except Exception as e:
logger.error(f"更新字典类型异常: {str(e)}")
return R.failed(msg="更新字典类型失败,请稍后重试")
if not result:
raise BizError("更新失败")
# ============================================================
# 字典类型删除
# ============================================================
def delete_dicts(dict_ids):
def delete_dicts(dict_ids: str) -> int:
"""
删除字典类型(批量删除)
@@ -374,8 +328,10 @@ def delete_dicts(dict_ids):
Returns:
R: 操作结果
"""
return Dict.batch_delete_r(dict_ids)
dict_ids_list = parse_id_list(dict_ids)
if not dict_ids_list:
raise BizError("无效的记录ID")
return Dict.batch_delete(dict_ids_list)
"""
@@ -399,23 +355,6 @@ def delete_dicts(dict_ids):
3. 数据维护:字典项的添加、更新、删除(支持批量)
"""
import logging
from datetime import datetime, timezone
from flask import request
from sqlalchemy import and_
from src.common.constants.common import PAGE_SIZE
from src.modules.dictionary.schema import DictItemForm
from src.modules.dictionary.models import Dict
from src.modules.dictionary.models import DictItem
from src.core.database import db
from src.core import response as R
from src.common.utils import regular
from src.common.utils.case_converter import convert_camel_to_snake
from src.common.utils.model_utils import models_to_list, model_to_dict
from src.common.utils.request import parse_request_body, parse_id_list, like_contains
from src.core.security import get_username
# 获取日志记录器
logger = logging.getLogger(__name__)
@@ -425,7 +364,8 @@ logger = logging.getLogger(__name__)
# 字典项分页查询
# ============================================================
def get_dict_item_page():
def get_dict_item_page(params: dict) -> dict:
"""
查询字典项分页数据
@@ -447,31 +387,26 @@ def get_dict_item_page():
"pages": 总页数
}
"""
try:
# 获取分页参数
page_no = int(request.args.get('pageNo', 1))
page_size = int(request.args.get('pageSize', PAGE_SIZE))
# 获取分页参数
page_no = int(params.get("pageNo", 1))
page_size = int(params.get("pageSize", PAGE_SIZE))
# 应用筛选条件
query = _apply_filters()
# 应用筛选条件
query = _apply_dict_item_filters(params)
# 记录总数
total = query.count()
# 计算总页数
pages = (total + page_size - 1) // page_size if total > 0 else 0
# 记录总数
total = query.count()
# 计算总页数
pages = (total + page_size - 1) // page_size if total > 0 else 0
# 分页查询
dict_item_list = query.limit(page_size).offset((page_no - 1) * page_size).all()
# 构建返回数据
page_data = _build_page_data(dict_item_list, total, page_size, page_no, pages)
return R.ok(data=page_data)
except Exception as e:
logger.error(f"查询字典项分页数据异常: {str(e)}")
return R.failed(msg="查询失败,请稍后重试")
# 分页查询
dict_item_list = query.limit(page_size).offset((page_no - 1) * page_size).all()
# 构建返回数据
page_data = _build_dict_item_page_data(dict_item_list, total, page_size, page_no, pages)
return page_data
def _apply_filters():
def _apply_dict_item_filters(params: dict):
"""
应用查询筛选条件
@@ -489,17 +424,17 @@ def _apply_filters():
query = DictItem.query.filter(DictItem.is_delete == 0)
# 字典ID筛选(必填)
dict_id = request.args.get('dictId', 0)
dict_id = params.get("dictId", 0)
if dict_id:
query = query.filter(DictItem.dict_id == dict_id)
# 字典项名称模糊筛选
name = request.args.get('name')
name = params.get("name")
if name:
query = query.filter(DictItem.name.like(like_contains(name), escape='\\'))
query = query.filter(DictItem.name.like(like_contains(name), escape="\\"))
# 字典项状态精确筛选
status = request.args.get('status')
status = params.get("status")
if status:
query = query.filter(DictItem.status == status)
@@ -507,7 +442,7 @@ def _apply_filters():
return query.order_by(DictItem.sort.asc())
def _build_page_data(dict_item_list, total, page_size, page_no, pages):
def _build_dict_item_page_data(dict_item_list, total, page_size, page_no, pages):
"""
构建分页返回数据
@@ -524,19 +459,14 @@ def _build_page_data(dict_item_list, total, page_size, page_no, pages):
# 将模型对象列表转换为字典列表
records = models_to_list(dict_item_list)
return {
'records': records,
'total': total,
'size': page_size,
'current': page_no,
'pages': pages
}
return {"records": records, "total": total, "size": page_size, "current": page_no, "pages": pages}
# ============================================================
# 字典项详情查询
# ============================================================
def get_dict_item_detail(dict_item_id):
"""
根据ID查询字典项详情(返回字典格式)
@@ -552,7 +482,7 @@ def get_dict_item_detail(dict_item_id):
"""
try:
# 复用 get_info 方法查询字典项
dict_item = get_info(dict_item_id)
dict_item = get_dict_item_info(dict_item_id)
if not dict_item:
return None
# 转换为字典格式
@@ -567,7 +497,8 @@ def get_dict_item_detail(dict_item_id):
# 字典项信息查询(根据ID)- 核心查询方法
# ============================================================
def get_info(dict_item_id: int):
def get_dict_item_info(dict_item_id: int):
"""
根据ID查询字典项信息(返回模型对象)
@@ -587,30 +518,14 @@ def get_info(dict_item_id: int):
DictItem/None: 字典项模型对象,不存在或已删除时返回 None
Example:
dict_item = get_info(dict_item_id)
dict_item = get_dict_item_info(dict_item_id)
if dict_item:
print(dict_item.name)
"""
# 参数有效性验证
if not dict_item_id or dict_item_id <= 0:
return None
try:
# 查询未删除的字典项
dict_item = DictItem.query.filter(
and_(DictItem.id == dict_item_id, DictItem.is_delete == 0)
).first()
return dict_item
except Exception as e:
logger.error(f"查询字典项信息异常,ID: {dict_item_id}, 错误: {str(e)}")
return None
return DictItemRepository.get_by_id(dict_item_id)
# ============================================================
# 字典项添加
# ============================================================
def add_dict_item():
def add_dict_item(data: dict) -> None:
"""
添加字典项
@@ -622,42 +537,31 @@ def add_dict_item():
Returns:
R: 操作结果
"""
try:
# 获取参数
json_data, error = parse_request_body()
if error:
return R.failed(msg=error)
# 表单验证
form = DictItemForm(data=json_data)
if not form.validate():
err_msg = regular.get_err(form)
return R.failed(msg=err_msg)
# 表单验证
form = DictItemForm(data=data)
if not form.validate():
raise BizError(regular.get_err(form))
# 查询配置(验证配置是否存在)
dict_id = form.dictId.data
dict = Dict.query.filter(Dict.id == dict_id).first()
if not dict:
return R.failed(msg="字典不存在")
# 查询配置(验证配置是否存在)
dict_id = form.dictId.data
dict = Dict.query.filter(Dict.id == dict_id).first()
if not dict:
raise BizError("字典不存在")
# 创建字典项
dict_item = DictItem(**form.data)
dict_item.dict_code = dict.code
dict_item.create_user = get_username()
dict_item.save()
return R.ok(msg="添加成功")
except Exception as e:
logger.error(f"添加字典项异常: {str(e)}")
return R.failed(msg="添加失败,请稍后重试")
# 创建字典项
dict_item = DictItem(**form.data)
dict_item.dict_code = dict.code
dict_item.create_user = get_username()
dict_item.save()
# ============================================================
# 字典项更新
# ============================================================
def update_dict_item():
def update_dict_item(data: dict) -> None:
"""
更新字典项
@@ -670,52 +574,42 @@ def update_dict_item():
Returns:
R: 操作结果
"""
try:
# 获取参数
json_data, error = parse_request_body()
if error:
return R.failed(msg=error)
# 表单验证
form = DictItemForm(data=json_data)
if not form.validate():
return R.failed(msg=regular.get_err(form))
# 表单验证
form = DictItemForm(data=data)
if not form.validate():
raise BizError(regular.get_err(form))
# 获取字典项ID
dict_item_id = form.data.get('id')
if not dict_item_id or int(dict_item_id) <= 0:
return R.failed("字典项ID无效")
dict_item_id = int(dict_item_id)
# 获取字典项ID
dict_item_id = form.data.get("id")
if not dict_item_id or int(dict_item_id) <= 0:
raise BizError("字典项ID无效")
dict_item_id = int(dict_item_id)
# 复用 get_info 方法验证字典项是否存在
dict_item = get_info(dict_item_id)
if not dict_item:
return R.failed("字典项不存在")
# 复用 get_info 方法验证字典项是否存在
dict_item = get_dict_item_info(dict_item_id)
if not dict_item:
raise BizError("字典项不存在")
# 更新字典项信息(移除ID,避免更新主键)
form_data = convert_camel_to_snake(form.data.copy())
form_data.pop('id', None)
# 更新字典项信息(移除ID,避免更新主键)
form_data = convert_camel_to_snake(form.data.copy())
form_data.pop("id", None)
form_data['update_time'] = datetime.now(tz=timezone.utc)
form_data['update_user'] = get_username()
form_data["update_time"] = datetime.now(tz=timezone.utc)
form_data["update_user"] = get_username()
result = DictItem.query.filter_by(id=dict_item_id).update(form_data)
result = DictItem.query.filter_by(id=dict_item_id).update(form_data)
if not result:
return R.failed("更新失败")
return R.ok(msg="更新成功")
except Exception as e:
logger.error(f"更新字典项异常: {str(e)}")
return R.failed(msg="更新字典项失败,请稍后重试")
if not result:
raise BizError("更新失败")
# ============================================================
# 字典项删除
# ============================================================
def delete_dict_items(dict_item_ids):
def delete_dict_items(dict_item_ids: str) -> int:
"""
删除字典项(批量删除)
@@ -728,4 +622,7 @@ def delete_dict_items(dict_item_ids):
Returns:
R: 操作结果
"""
return DictItem.batch_delete_r(dict_item_ids)
dict_item_ids_list = parse_id_list(dict_item_ids)
if not dict_item_ids_list:
raise BizError("无效的记录ID")
return DictItem.batch_delete(dict_item_ids_list)
+1 -1
View File
@@ -33,6 +33,7 @@ from src.common.constants.dictionary_constants import (
from src.modules.log.models import LoginLog, OperationLog
from src.modules.log.login_log_repository import LoginLogRepository
from src.modules.log.operation_log_repository import OperationLogRepository
from src.core.database import commit_independently
from src.core.exceptions import BizError
from src.common.utils.model_utils import models_to_list, model_to_dict
from src.common.utils.request import parse_id_list, like_contains
@@ -559,7 +560,6 @@ def record_operation_log(title, log_type, source, status, **kwargs):
# 使用独立session写入,不受请求事务影响
# 日志是审计数据,无论业务成功或失败都应持久化
from src.core.database import commit_independently
commit_independently(log)