Django REST Framework API除以零导致NaN问题的解决方案咨询
解决Django REST Framework中除以零导致的API异常问题
这是数值计算里很常见的边界场景,咱们可以通过提前校验除数+友好错误反馈+代码安全优化三个维度来彻底解决,同时避免潜在的安全风险。
核心问题分析
你的代码里直接执行((sales_all - sales_p)/sales_c)*100,当sales_c为0时会触发除以零的运算,生成NaN,最终导致API返回异常(可能是500错误或不符合预期的响应)。另外还有两个隐藏问题:
- 直接拼接用户输入的
input_date到SQL语句中,存在SQL注入风险 - 代码里出现了笔误:
df5['sales_c'].loc[0]应该是df['sales_c'].loc[0],否则会抛出NameError
最优处理方案
下面是修改后的完整代码,包含所有优化点:
from rest_framework import status from rest_framework.response import Response from rest_framework.exceptions import ServiceUnavailable def your_api_view(request): input_date = request.query_params.get('date') # 假设从查询参数获取日期 dept_id = request.query_params.get('dept_id') # 假设从查询参数获取部门编号 # 1. 使用参数化SQL避免注入风险(替换原来的字符串拼接) sql = "select sales_p, sales_c, sales_all from sales where dat_ref = %s and dept_id = %s" try: # 假设select_vector支持接收params参数传递查询值 df = select_vector(sql, DB_CONNECTOR, params=(input_date, dept_id)) except Exception: raise ServiceUnavailable() if df is None: raise ServiceUnavailable() if len(df) > 0: sales_p = df['sales_p'].loc[0] sales_c = df['sales_c'].loc[0] # 修正原代码的df5笔误 sales_all = df['sales_all'].loc[0] else: return Response(status=status.HTTP_204_NO_CONTENT) # 2. 提前校验除数是否为0,避免NaN异常 if sales_c == 0: return Response( { 'error': '无法计算销售指标百分比', 'detail': '对应日期和部门的sales_c字段值为0,除数不能为零' }, status=status.HTTP_400_BAD_REQUEST ) # 3. 安全计算百分比,额外捕获数值转换异常 try: percentage_value = ((sales_all - sales_p) / sales_c) * 100 percentage = float("{0:.2f}".format(percentage_value)) except (TypeError, ValueError) as e: return Response( { 'error': '销售指标计算失败', 'detail': f'数值计算出错:{str(e)}' }, status=status.HTTP_400_BAD_REQUEST ) return Response({'Percentage': percentage})
关键优化点说明
- 参数化SQL查询:不再直接拼接用户输入的日期和部门编号,而是通过参数传递,彻底避免SQL注入攻击,这是后端开发的必备安全规范。
- 提前除数校验:在计算前先判断
sales_c是否为0,直接返回清晰的错误信息给用户,而不是让程序抛出未处理的异常。 - 异常兜底处理:捕获数值转换或计算时的TypeError/ValueError,比如字段值不是数值类型的情况,确保API始终返回结构化的响应。
- 修正代码笔误:把原代码中的
df5改为df,避免不必要的NameError。
响应说明
用户遇到除数为0的情况时,会收到如下结构化响应(HTTP 400状态码):
{ "error": "无法计算销售指标百分比", "detail": "对应日期和部门的sales_c字段值为0,除数不能为零" }
这样用户能明确知道问题所在,而不是收到模糊的500错误或异常响应。
内容的提问来源于stack exchange,提问作者S.Jackson
相关产品推荐
相关产品推荐

