【问题标题】:Include a function with render in another view function在另一个视图函数中包含一个带有渲染的函数
【发布时间】:2021-04-13 14:14:49
【问题描述】:

我想在视图中设计一个错误处理函数,并在视图中不同的主要功能中使用它。 此错误处理函数将收集所需的错误信息,将错误记录到系统,并将这些信息呈现到错误处理页面。

view.py 中的代码如下:

def error_manage(request, error_title, error_detail):
    error_time = datetime.now()
    info_table = {'error_title': error_title,
                     'error_detail': error_detail,
                     'error_time ': error_time ,
                     }
    logger.error(str(error_detail))
    return render(request,'home/error_manage.html', {'error_title': error_title, 
                                                     'info_table ': display_table})


def my_page_1(request):
    try:
        var1 = my_calculation_func()
    except Exception as ex:
        error_manage(request, "Unexpected Error Happened.", ex)
    
    var2 = my_calculation_func2()
    var3 = my_calculation_func3()
    return render(request,'home/my_page_1.html', {'var1': var1 ,'var2': var2 ,'var3': var3})

这里的问题是,当var1发生错误时,程序会跳转到error_manage,但不会在这个函数的返回中停止,也不会成功渲染到error_manage.html中。

它稍后会跳出这个函数并继续运行 var2 和 var3,直到它遇到 my_page_1() 中的最终返回。

我知道我可以简单地将error_manage 中的return 语句放在异常下的my_page_1 中。 但是这个错误处理程序将在 view.py 中的许多其他函数中使用,我不想一遍又一遍地重复它。

这个问题有好的解决方案吗?谢谢。

【问题讨论】:

  • 我会将您的错误处理程序编写为装饰器函数,然后将其用作您要使用它的视图的装饰器。
  • 也许你需要raise自定义异常?

标签: python django error-handling django-views


【解决方案1】:

以下是装饰器方法的示例:

class MyError(Exception):
    pass


def error_handler(func):
    def decorated(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except MyError as e:
            return f"Oh no! {e} happened!"
    return decorated


@error_handler
def my_view(request):
    if "error" in request:
        raise MyError("request was rubbish")
    return "Great success!"


for r in ["Fine", "no problem", "An error happened"]:
    print(my_view(r))

所以运行这个,我们得到

Great success!
Great success!
Oh no! request was rubbish happened!

所以本质上我们使用装饰器来捕获和处理 MyError 异常,其他异常将不会被处理,并且会像往常一样从视图中冒出来,由 django 的 [default] 视图错误处理来处理。

【讨论】:

  • 喜欢使用装饰器 - 不知道为什么会被淘汰
  • 感谢您的回答。我试图在我的代码中实现这一点,但我有一个问题:我可以放置我想要呈现的错误变量,例如 error_detail(通过 error_detail=str(e))和 error_time(通过 error_time = datetime.now()) ,在 def error_handler() 的“except”行下,然后渲染到我想要的错误处理页面。但是我如何传递根据不同的错误情况非常定制的 error_title 。 (在我的问题情况下,它是“发生意外错误。”但对于其他错误情况可能会有所不同)
  • 如果您希望每个视图显示不同的错误消息,那么您可以使用参数化装饰器geeksforgeeks.org/decorators-with-parameters-in-python
【解决方案2】:

您应该制作一个自定义中间件来处理异常。见Writing your own middleware [Django docs]

class MyMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        return response
    
    def process_exception(request, exception):
        error_time = datetime.now()
        info_table = {
            'error_detail': exception,
            'error_time ': error_time ,
        }
        logger.error(str(exception))
        return render(request,'home/error_manage.html', {'info_table ': display_table})

现在您需要将此中间件添加到设置中的MIDDLEWARE 列表中:

MIDDLEWARE = [
    # Default middlewares
    'path.to.MyMiddleware',
]

现在在您看来,您不应该捕获异常并让中间件处理它。

注意:通过这种方式,您传递 error_title 的方法将不起作用,但您可以尝试从旧异常中重新引发新异常,如果您 需要一些定制:raise Exception("Unexpected Error Happened.") from ex

【讨论】:

  • 这个问题是它被应用于每个视图,这可能不是OP想要的。
  • @TomDalton 是的,但没有什么是 if-else 无法解决的。 request 被传递给process_exception,因此可以很容易地找出哪个视图引发了这个异常。 :)
  • 是的,但是当(个人)我希望中间件做更多通用/通用的事情时,您会将中间件耦合到特定的应用程序。
  • @TomDalton 错误处理是一般的东西。这就是为什么process_exception 方法甚至存在于中间件上的原因......
  • 是的,我并不是说这是完全错误的,我只是说 OP 并不清楚他们是否希望以这种方式自动处理每个视图。也许他们有,也许他们没有。
猜你喜欢
  • 2021-03-26
  • 2010-10-17
  • 1970-01-01
  • 2021-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-20
相关资源
最近更新 更多