handle_exception.py 4.0 KB

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