handle_exception.py 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. # coding=utf-8
  2. """
  3. @project: qabot
  4. @Author:虎
  5. @file: handle_exception.py
  6. @date:2023/9/5 19:29
  7. @desc:
  8. """
  9. import logging
  10. import traceback
  11. from rest_framework.exceptions import ValidationError, ErrorDetail, APIException
  12. from rest_framework.views import exception_handler
  13. from common.exception.app_exception import AppApiException
  14. from django.utils.translation import gettext_lazy as _
  15. from common.result import result
  16. from common.utils.logger import maxkb_logger
  17. def to_result(key, args, parent_key=None):
  18. """
  19. 将校验异常 args转换为统一数据
  20. :param key: 校验key
  21. :param args: 校验异常参数
  22. :param parent_key 父key
  23. :return: 接口响应对象
  24. """
  25. error_detail = list(filter(
  26. lambda d: True if isinstance(d, ErrorDetail) else True if isinstance(d, dict) and len(
  27. d.keys()) > 0 else False,
  28. (args[0] if len(args) > 0 else {key: [ErrorDetail(_('Unknown exception'), code='unknown')]}).get(key)))[0]
  29. if isinstance(error_detail, dict):
  30. return list(map(lambda k: to_result(k, args=[error_detail],
  31. parent_key=key if parent_key is None else parent_key + '.' + key),
  32. error_detail.keys() if len(error_detail) > 0 else []))[0]
  33. return result.Result(500 if isinstance(error_detail.code, str) else error_detail.code,
  34. message=f"【{key if parent_key is None else parent_key + '.' + key}】为必填参数" if str(
  35. error_detail) == "This field is required." else error_detail)
  36. def validation_error_to_result(exc: ValidationError):
  37. """
  38. 校验异常转响应对象
  39. :param exc: 校验异常
  40. :return: 接口响应对象
  41. """
  42. try:
  43. v = find_err_detail(exc.detail)
  44. if v is None:
  45. return result.error(str(exc.detail))
  46. return result.error(str(v))
  47. except Exception as e:
  48. return result.error(str(exc.detail))
  49. def find_err_detail(exc_detail):
  50. if isinstance(exc_detail, ErrorDetail):
  51. return exc_detail
  52. if isinstance(exc_detail, dict):
  53. keys = exc_detail.keys()
  54. for key in keys:
  55. _value = exc_detail[key]
  56. if isinstance(_value, list):
  57. return find_err_detail(_value)
  58. if isinstance(_value, ErrorDetail):
  59. return _value
  60. if isinstance(_value, dict) and len(_value.keys()) > 0:
  61. return find_err_detail(_value)
  62. if isinstance(exc_detail, list):
  63. for v in exc_detail:
  64. r = find_err_detail(v)
  65. if r is not None:
  66. return r
  67. def handle_exception(exc, context):
  68. exception_class = exc.__class__
  69. # 先调用REST framework默认的异常处理方法获得标准错误响应对象
  70. response = exception_handler(exc, context)
  71. # 在此处补充自定义的异常处理
  72. if issubclass(exception_class, ValidationError):
  73. return validation_error_to_result(exc)
  74. if issubclass(exception_class, AppApiException):
  75. return result.Result(exc.code, exc.message, response_status=exc.status_code)
  76. if issubclass(exception_class, APIException):
  77. return result.error(exc.detail)
  78. if response is None:
  79. maxkb_logger.error(f'{str(exc)}:{traceback.format_exc()}')
  80. return result.error(str(exc))
  81. return response