Django报request参数非HttpRequest实例(OrderedDict)错误排查
报错根因
这个报错和你贴出的服务层业务逻辑无关,核心触发原因是同名函数覆盖导致的调用错误:
- 你先通过
from custom_label.services.custom_label_svc import update_label导入了服务层的更新函数 - 紧接着你定义的视图函数本身也命名为
update_label,直接在全局作用域覆盖了之前导入的服务层函数 - 当你执行
update_label(payload.validated_data)时,实际调用的是视图函数本身,而非服务层函数。视图函数的第一个位置参数要求传入django.http.HttpRequest实例,你传入的是序列化器校验后返回的OrderedDict类型数据,自然触发参数类型不匹配的报错。 - 其他业务模块运行正常,是因为那些模块的视图函数名和导入的服务层函数名不存在重名,没有触发覆盖问题。
另外你贴的服务层代码还存在几个会导致线上异常的隐患,和当前报错无关但必须修复:
- 数据库连接、游标在模块全局作用域初始化,会被所有请求共享,服务长时间运行后会出现连接超时、事务错乱、游标状态污染等问题
- SQL语句通过字符串格式化拼接参数,存在明确的SQL注入风险
- 写操作没有事务提交逻辑,即使SQL执行成功,修改也不会实际落库
- 函数返回值标注错误,
cursor.rowcount是整数类型,不是dict
修复方案
1. 解决命名冲突(修复当前报错)
两种方案选其一即可:
方案一:给导入的服务层函数加别名
修改导入语句,避免和视图函数重名:
# 视图层修改导入语句 from custom_label.services.custom_label_svc import update_label as update_label_svc @api_view(["POST"]) @authorize def update_label(request) -> JsonResponse: try: payload = ValidateUpdateLabel(data=request.data) if payload.is_valid(): # 调用时使用别名 data = update_label_svc(payload.validated_data) # 其余业务逻辑保持不变
方案二:修改视图函数名
将视图函数重命名为不和服务层函数冲突的名称,注意同步修改路由配置中对该视图的引用:
from custom_label.services.custom_label_svc import update_label @api_view(["POST"]) @authorize def update_label_view(request) -> JsonResponse: # 修改视图函数名 try: payload = ValidateUpdateLabel(data=request.data) if payload.is_valid(): data = update_label(payload.validated_data) # 其余业务逻辑保持不变
2. 修复服务层数据库逻辑隐患
调整服务层代码,将数据库连接初始化移到函数内部,改用参数化查询,补充事务提交/回滚和资源释放逻辑:
from basic_files.database_connections import connect_to_postges def update_label(params: dict) -> int: app_id = params.get('appid') label_name = params.get('label_name') updated_label_icon = params.get('updated_label_icon') conn = None cursor = None try: # 每次请求单独创建连接,避免连接复用问题 conn = connect_to_postges() cursor = conn.cursor() # 参数化查询,杜绝SQL注入 sql = "UPDATE label SET icon = %s WHERE appId = %s AND name = %s" cursor.execute(sql, (updated_label_icon, app_id, label_name)) conn.commit() # 写操作必须提交事务才会落库 return cursor.rowcount except Exception as e: if conn: conn.rollback() # 异常时回滚事务 raise e finally: # 释放游标和连接 if cursor: cursor.close() if conn: conn.close()
内容的提问来源于stack exchange,提问作者Azima
相关产品推荐
相关产品推荐

