如何使 Django 模型原子性回滚在 4xx 或 5xx HTTP 状态代码上



我知道,django atomicity 开箱即用仅在抛出异常时才回滚事务。但是,我的脚本中捕获了几个异常,对于这些异常,我正在生成一个很好的 HTTPresponse,其中包含一些有意义的响应内容 - 但我始终确保在这种情况下的 HTTPresponse 以正确的 4xx 或 5xx HTTP 状态代码发送出去。当这样的HTTP响应发生时,我希望django回滚它到目前为止可能执行的所有数据库查询。但是,django atomicity 似乎并不基于正在发送的 HTTP 状态代码起作用,它仅基于抛出给用户的异常起作用。任何建议我如何在python 2.7 django 1.8解决这个问题?

尝试创建一个自定义中间件来执行此操作。下面是一个基于旧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...
)

最新更新