【问题标题】:how to make django model atomicity rollback upon 4xx or 5xx HTTP status codes如何在 4xx 或 5xx HTTP 状态码上使 django 模型原子性回滚
【发布时间】:2016-06-11 21:07:21
【问题描述】:

我了解,开箱即用的 django atomicity 仅在抛出异常时才会回滚事务。但是,我在脚本中捕获了几个例外情况,对于这些例外情况,我正在生成一个不错的 HTTPresponse,并为用户提供一些有意义的响应内容——但我始终确保在这种情况下的 HTTPresponse 以正确的 4xx 发送出去或 5xx HTTP 状态代码。当这样的 HTTPresponse 发生时,我希望 django 回滚它可能执行到现在的所有数据库查询。但是,django 原子性似乎并不基于发送的 HTTP 状态代码,它仅基于向用户抛出的异常。有什么建议我可以在django 1.8python 2.7 上解决这个问题吗?

【问题讨论】:

    标签: python django python-2.7 django-models transactions


    【解决方案1】:

    尝试创建一个可以执行此操作的自定义中间件。这是一个based on the old TransactionMiddleware 的示例(未经测试):

    from django.db import transaction
    
    class StatusCodeTransactionMiddleware(object):
        """
        Rolls back the current transaction for all responses with 4xx or 5xx status
        codes.
        """
    
        def process_request(self, request):
            """Enters transaction management"""
            transaction.enter_transaction_management()
    
        def process_response(self, request, response):
            """Commits and leaves transaction management."""
            if response.status_code >= 400:
                if transaction.is_dirty():
                    # This rollback might fail because of network failure for
                    # example. If rollback isn't possible it is impossible to
                    # clean the connection's state. So leave the connection in
                    # dirty state and let request_finished signal deal with
                    # cleaning the connection.
                    transaction.rollback()
                transaction.leave_transaction_management()
            else:
                if not transaction.get_autocommit():
                    if transaction.is_dirty():
                        # Note: it is possible that the commit fails. If the
                        # reason is closed connection or some similar reason,
                        # then there is little hope to proceed nicely.
                        # However, in some cases ( deferred foreign key checks
                        # for example) it is still possible to rollback().
                        try:
                            transaction.commit()
                        except Exception:
                            # If the rollback fails, the transaction state will
                            # be messed up. It doesn't matter, the connection
                            # will be set to clean state after the request
                            # finishes. And, we can't clean the state here
                            # properly even if we wanted to, the connection is
                            # in transaction but we can't rollback...
                            transaction.rollback()
                            transaction.leave_transaction_management()
                            raise
                    transaction.leave_transaction_management()
            return response
    

    像这样把它放在你的MIDDLEWARE_CLASSES 中:

    MIDDLEWARE_CLASSES = (
        "myapp.middleware.StatusCodeTransactionMiddleware",
        # Other middleware...
    )
    

    【讨论】:

    • 看起来不错...我会试试这个并相应更新
    • btw @grantmcconnaughey,enter_transaction_management() 是反式启动, leave_transaction_management() 是 COMMIT?
    • 我也将“ATOMIC_REQUEST”设置为 TRUE。这会干扰吗?
    • 完成。它现在提交。同样,这一切都是从旧的TransactionMiddleware 类中提取的,还没有经过测试。我不认为我会使用ATOMIC_REQUESTS,因为它几乎做同样的事情,但我不认为它会受到伤害。您甚至可以更新此中间件以在出现异常时回滚事务,这意味着它将同时处理状态代码 >= 400 和请求/响应周期中的异常。如果你这样做,那么我肯定会将ATOMIC_REQUESTS 设置为False
    • 需要存储在middleware.py中,而不是RequestResponseTransaction.py中。 RequestResponseTransaction 是类的名称,中间件是它所在模块的名称。查看 Django MIDDLEWARE_CLASSES 的其他示例以了解我的意思。
    猜你喜欢
    • 1970-01-01
    • 2012-10-02
    • 2011-05-21
    • 2011-10-02
    • 1970-01-01
    • 2014-02-03
    • 2019-07-04
    • 2011-07-17
    • 1970-01-01
    相关资源
    最近更新 更多