【发布时间】:2016-06-25 18:38:24
【问题描述】:
我有一个我想要的视图:
1. 保存模型实例
2. 可能保存更多模型实例
如果 1 或 2 有任何问题,则回滚 1 和 2。
无论我使用 transaction.savepoint() 还是使用嵌套的 transaction.atomic() 调用,我最终都会收到 TransactionManagementError。
查看 - 使用 transaction.savepoint()
@transaction.atomic
def my_view(request):
foo = Foo()
sid1 = transaction.savepoint()
foo.save()
if foo.whatever:
error = 'blah'
sid2 = transaction.savepoint()
foo.create_saved_instances() # creates more saved Foo instances in a separeate func
if foo.something_else:
error = 'baz'
if error:
transaction.savepoint_rollback(sid1)
else:
transaction.savepoint_commit(sid2)
...
查看 - 使用 transaction.atomic()
@transaction.atomic
def my_view(request):
foo = Foo()
try:
with transaction.atomic():
foo.save()
if foo.whatever:
error = 'blah'
try:
with transaction.atomic():
foo.create_saved_instances() # creates more saved Foo instances in a separeate func
if foo.something_else:
error = 'baz'
if error:
raise ValidationError
except ValidationError:
pass
if error:
raise ValidationError
except ValidationError:
pass
...
追溯
我使用 transaction.savepoint() 或 transaction.atomic() 得到一个 TransactionManagementError
下面是transaction.savepoint()的回溯
File ".../lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
149. response = self.process_exception_by_middleware(e, request)
File ".../lib/python2.7site-packages/django/core/handlers/base.py" in get_response
147. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "...//project/users/decorators.py" in func
64. return view_func(request, *args, **kwargs)
File ".../lib/python2.7site-packages/django/utils/decorators.py" in inner
184. return func(*args, **kwargs)
File ".../project/employers/views/shiftcal.py" in my_view
238. transaction.savepoint_rollback(sid1)
File ".../lib/python2.7site-packages/django/db/transaction.py" in savepoint_rollback
66. get_connection(using).savepoint_rollback(sid)
File ".../lib/python2.7site-packages/django/db/backends/base/base.py" in savepoint_rollback
328. self._savepoint_rollback(sid)
File ".../lib/python2.7site-packages/django/db/backends/base/base.py" in _savepoint_rollback
288. cursor.execute(self.ops.savepoint_rollback_sql(sid))
File ".../lib/python2.7site-packages/djangodb/backends/utils.py" in execute
79. return super(CursorDebugWrapper, self).execute(sql, params)
File ".../lib/python2.7site-packages/django/db/backends/utils.py" in execute
59. self.db.validate_no_broken_transaction()
File ".../lib/python2.7site-packages/django/db/backends/base/base.py" in validate_no_broken_transaction
429. "An error occurred in the current transaction. You can't "
Exception Type: TransactionManagementError at /my-view/
Exception Value: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.
下面是 transaction.atomic() 的回溯
Traceback:
File "../lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
149. response = self.process_exception_by_middleware(e, request)
File "../lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
147. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File ".../project/users/decorators.py" in func
64. return view_func(request, *args, **kwargs)
File "../lib/python2.7/site-packages/django/utils/decorators.py" in inner
184. return func(*args, **kwargs)
File "../project/employers/views/my_view.py" in my_view
178. foo.create_saved_instances()
File "../project/jobs/models.py" in create_saved_instances
2685. foo.save()
File "../project/jobs/models.py" in save
2364. super(Foo, self).save(*args, **kwargs)
File "../lib/python2.7/site-packages/django/db/models/base.py" in save
700. force_update=force_update, update_fields=update_fields)
File "../lib/python2.7/site-packages/django/db/models/base.py" in save_base
728. updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "../lib/python2.7/site-packages/django/db/models/base.py" in _save_table
812. result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "../lib/python2.7/site-packages/django/db/models/base.py" in _do_insert
851. using=using, raw=raw)
File "../lib/python2.7/site-packages/django/db/models/manager.py" in manager_method
122. return getattr(self.get_queryset(), name)(*args, **kwargs)
File "../lib/python2.7/site-packages/django/db/models/query.py" in _insert
1039. return query.get_compiler(using=using).execute_sql(return_id)
File "../lib/python2.7/site-packages/django/db/models/sql/compiler.py" in execute_sql
1060. cursor.execute(sql, params)
File "../lib/python2.7/site-packages/django/db/backends/utils.py" in execute
79. return super(CursorDebugWrapper, self).execute(sql, params)
File "../lib/python2.7/site-packages/django/db/backends/utils.py" in execute
59. self.db.validate_no_broken_transaction()
File "../lib/python2.7/site-packages/django/django/db/backends/base/base.py" in validate_no_broken_transaction
429. "An error occurred in the current transaction. You can't "
Exception Type: TransactionManagementError at /my-view/
Exception Value: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.
有什么方法可以回滚所有事务而不出现 TransactionManagementError?
【问题讨论】:
-
使用
atomic的代码的回溯是什么。我认为您不应该手动引发IntegrityError,而是尝试引发不同的异常。 -
最后我必须为 ajax 返回一个 HttpResponse(some_error, status=status) - 如果我创建一个错误,我会手动提出错误,以便可以轻松地将该错误传回,而不是返回一个错误字典(在我看来也有一个表格......它有点乱)
-
@Alasdair - 我添加了 transaction.atomic 的回溯 - 谢谢。
-
回溯显示错误发生在
create_saved_instances方法中,但您还没有显示代码。该方法中是否有应该包装在原子块中的代码? -
看来你想通了。如果需要,您可以在
create_saved_instances方法中捕获完整性错误,但如果您决定这样做,则应将new_instance.save()包装在另一个transaction.atomic()块中。这个想法在docs for atomic 中有解释(参见示例代码和注释)。
标签: django