在Django / Python应用程序中设计适当的错误处理代码?

问题描述 投票:2回答:2

我正在构建一个Django应用程序,我希望得到一些关于处理我的代码中的错误和错误的正确方法的建议。

以下是我遇到的问题的常见情况:用户购买产品。要处理购买,我的观点需要执行许多操作:

  1. 首先,视图应该在数据库中创建一个User对象。
  2. 如果成功,视图应创建一个Order对象并将其分配给新创建的用户。
  3. 如果成功,我的代码应该创建一个Product对象并将其添加到新创建的Order中。

当没有错误发生时,这一切都很好 - 但我发现偶然的错误在我的代码中是不可避免的,我希望我的应用程序优雅地处理错误,而不是直接崩溃。例如,如果由于任何原因无法创建Order对象,则视图应向用户显示错误并删除先前创建的User对象。并且,它应该抛出一个优雅的错误消息,而不是直接崩溃并为用户提供Http 500错误。

我能想到的唯一方法是使用一系列非常复杂的嵌套try / except子句,如下所示。但是以这种方式设计我的代码是非常混乱和耗时的,并且它不是正确的做事方式。我知道必须有更好的方法来设计Django和Python中的正确错误处理,但我不太确定它是什么。

我非常感谢有关如何在这种情况下更好地构建代码的任何建议。

示例代码:

try:

    # Create a new user
    u = User(email='[email protected]')
    u.save()

    try:

        # Create a new order
        o = Order(user=u, name='Order name')
        o.save()

        try:

            # Create a new product
            p = Product(order=o, name='Product name')
            p.save()

        # If a product cannot be created, print an error message and try deleting the user and order that were previously created
        except:

            messages.add_message(request, messages.ERROR, 'Product could not be created')

            # If deleting the order doesn't work for any reason (for example, o.save() didn't properly save the user), 'pass' to ensure my application doesn't crash
            try:
                o.delete()

            # I use these 'except: pass' clauses to ensure that if an error occurs, my app doesn't serve a Http 500 error and instead shows the user a graceful error
            except:
                pass

            # If deleting the user doesn't work for any reason (for example, u.save() didn't properly save the user), 'pass' to ensure my application doesn't crash
            try:
                u.delete()
            except:
                pass

    # If an order cannot be created, print an error message and try deleting the user that was previously created
    except:
        messages.add_message(request, messages.ERROR, 'Order could not be created')

        # If deleting the user doesn't work for any reason (for example, u.save() didn't properly save the user), 'pass' to ensure my application doesn't crash
        try:
            u.delete()
        except:
            pass

# If the user cannot be created, throw an error
except:
    messages.add_message(request, messages.ERROR, 'User could not be created')
python django exception error-handling exception-handling
2个回答
3
投票

我建议使用transaction.atomic块,它应该包含你的模型创建(qjxswpoi来自django docs):

link

这样,在发生任何问题时,将自动回滚在上下文管理器内完成的任何更改。

附:实际上这是django默认处理每个视图的方式,但对于你的情况,你希望它失败然后你可以摆脱500错误,仍然得到干净的数据库,以防发生问题而不需要删除每个创建的对象。


-1
投票

这个怎么样?将您尝试创建的每个内容分配给try: with transaction.atomic(): create_your_objects() except IntegrityError: handle_exception() 。如果实例化它们(调用构造函数)会抛出异常,它们将保持None。另一方面,如果它们被正确实例化,但它们没有正确保存,那么它们的主键将是None。从而:

None

您可以通过循环遍历u,o和p的列表来进一步改进这一点并使其更具联系性,而不是像我那样重复代码,但这应该给你一般的想法。

顺便说一句:函数式编程提供了一些见解,因为纯函数式编程禁止异常抛出。这些语言有u = None o = None p = None try: # Create a new user u = User(email='[email protected]') u.save() # Create a new order o = Order(user=u, name='Order name') o.save() # Create a new product p = Product(order=o, name='Product name') p.save() except: if u == None or u.pk == None: messages.add_message(request, messages.ERROR, 'User could not be created') else if o == None or o.pk == None: messages.add_message(request, messages.ERROR, 'Order could not be created') else if p == None or p.pk == None: messages.add_message(request, messages.ERROR, 'Product could not be created') monads(名称可以变化),它基本上是一个包装类,它有两个可能的值:对象本身,或Maybe,它有一个方法None,它接受参数get_or_else,并返回它存储的对象,如果它存在,或foo如果它为null。你可以在Python中轻松实现这一点,但我相信它被认为是unpythonic。

© www.soinside.com 2019 - 2024. All rights reserved.