Python 错误处理:如何正确区分异常的优先级

Python 错误处理:如何正确区分异常的优先级,python,django-rest-framework,Python,Django Rest Framework,有两个功能:一个是下载excel文件(ExcelFileUploadView(APIView)),另一个是处理下载的文件(def parse\u excel\u rfi\u sheet)。 函数parse\u excel\u rfi\u sheet在ExcelFileUploadView(APIView) 问题是,当解析excel\u rfi\u工作表中发生错误时,我看不到调用{“常规错误”:[“excel文件解析期间出错。未知模块单元”]} 相反,我总是看到电话 {"general_error

有两个功能:一个是下载excel文件(
ExcelFileUploadView(APIView)
),另一个是处理下载的文件(
def parse\u excel\u rfi\u sheet
)。 函数
parse\u excel\u rfi\u sheet
ExcelFileUploadView(APIView)

问题是,当
解析excel\u rfi\u工作表中发生错误时,我看不到调用
{“常规错误”:[“excel文件解析期间出错。未知模块单元”]}
相反,我总是看到电话

{"general_errors": ["Error during file upload"]}
这就是为什么我不能理解错误是在什么阶段发生的:下载文件的时候还是处理文件的时候。
如何更改此设置?

因为您正在从
ExcelFileUploadView
调用
parse\u excel\u rfi\u sheet
,每当异常
{“general\u errors”:[“excel文件解析期间出错。未知模块单元”]}
parse_excel\u rfi_sheet
函数
try
中引发,从
ExcelFileUploadView
中阻止失败,并进入
之外,并引发异常
{“常规错误”:[“文件上载期间出错”]

您可以通过打印由
ExcelFileUploadView
函数引发的异常来验证这一点。 将try块更改为以下内容:

try:
    file = default_storage.save(filename, f)
    r = parse_excel_rfi_sheet(file)
    status = 200
except Exception as e:
    print("Exception raised ", e)
    raise Exception({"general_errors": ["Error during file upload"]})
引发异常(…)
生成一个新的
异常
实例并引发该实例。 这意味着,
尝试。。。除了
put
中的
,它有效地丢弃了捕获的异常,并将其替换为一个新的异常,并显示消息“文件上载时出错”,这就是为什么您总是看到相同的消息

处理此问题的一种干净方法是定义
异常
(例如,
无效格式异常
)的自定义子类,并在
parse\u excel\u rfi\u sheet
中提出该子类,在
put
中有两个不同的
案例除外:

class InvalidFormatException(Exception):
    pass

[...]

def parse_excel_rfi_sheet(file):
    workbook = load_workbook(filename=file)
    sheet = workbook["RFI"]
    curent_module_coordinate = []
    try:
        ....
        curent_module_coordinate.append(sheet['E688'].value)  
        curent_module_coordinate.append(sheet['E950'].value)  
        if check_exel_rfi_template_structure(structure=curent_module_coordinate):
            file_status = True
        else:
            file_status = False
    except:
        raise InvalidFormatException({"general_errors": ["Error during excel file parsing. Unknown module cell"]})
您的
put
将变成:

    def put(self, request, format=None):
        if 'file' not in request.data:
            raise ParseError("Empty content")
        f = request.data['file']
        filename = f.name
        if filename.endswith('.xlsx'):
            try:
                file = default_storage.save(filename, f)
                r = parse_excel_rfi_sheet(file)
                status = 200
            except InvalidFormatException:
                raise # pass on the exception
            except:
                raise Exception({"general_errors": ["Error during file upload"]})
            finally:
                default_storage.delete(file)
        else:
            status = 406
            r = {"general_errors": ["Please upload only xlsx files"]}
        return Response(r, status=status)

警告:正如对本答案的评论中所指出的,请注意,尽管没有直接询问,但应进一步修改OP的代码,以删除裸露的
,除了:
子句,如下所示

您的问题来自捕获绝对所有的异常,首先在
解析excel\rfi\u表
中,然后再次在
放置
方法中。裸except子句(
except:whatever_code_here
)和大的
try
块都是反模式-您只想捕获在给定点上期望的确切异常(使用
except(SomeExceptionType,AnotherExceptionType,…)例如e:
,并且在
try
块中拥有尽可能少的代码,这样您就有信心知道异常来自何处

此规则的唯一例外(没有双关语)是更高级别的“catch all”处理程序,用于捕获意外错误,记录这些错误(因此您可以跟踪发生的情况),并向用户显示一条友好的错误消息-但即使如此,您也不希望看到一个简单的except子句,而是希望看到一个
Exception作为e


TL;DR:永远不要假设发生了什么异常,发生在哪里,为什么发生,永远不要默默地传递异常(至少要记录它们,并检查日志).

关于使用bare except子句的异常处理的答案是一个非常糟糕的答案。正确的异常处理规则#1:永远不要使用bare except子句。@Brunodesshuilliers问题不是关于正确的异常处理,我不主张我的解决方案在“正确”方面是正确的异常处理,因为这与主题相去甚远。OP想知道为什么他的异常会被取消,我提供了一个例子来解释如何解决这个问题。深入研究OP代码中可能存在的错误是为了,而不是为了。@GPhilo但听起来它不像OP预期的那样工作,对CR无效。@Mast this questi当然,on不属于CR。我只是说,我正在详细说明OP的代码不好的原因(当然,除了请求的问题)会偏离主题。@GPhilo我想我们必须同意不同意。但还是要感谢您添加了警告。谢谢,我根据您添加的内容编写了一个审阅代码,现在我收到的是一个特定错误,而不是一般消息。
    def put(self, request, format=None):
        if 'file' not in request.data:
            raise ParseError("Empty content")
        f = request.data['file']
        filename = f.name
        if filename.endswith('.xlsx'):
            try:
                file = default_storage.save(filename, f)
                r = parse_excel_rfi_sheet(file)
                status = 200
            except InvalidFormatException:
                raise # pass on the exception
            except:
                raise Exception({"general_errors": ["Error during file upload"]})
            finally:
                default_storage.delete(file)
        else:
            status = 406
            r = {"general_errors": ["Please upload only xlsx files"]}
        return Response(r, status=status)