Django 1.6事务管理错误:当自动提交关闭时,数据库表现不正常

25

我正在尝试将一个项目从Django 1.5.5更新到Django 1.6,然而我无论做什么都会遇到这个错误。

Traceback (most recent call last):

File "project/virtualenv/lib/python2.7/site-packages/django/core/handlers/base.py", line 114, in get_response
  response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "project/virtualenv/lib/python2.7/site-packages/django/contrib/admin/sites.py", line 215, in wrapper
  return self.admin_view(view, cacheable)(*args, **kwargs)

File "project/virtualenv/lib/python2.7/site-packages/django/utils/decorators.py", line 99, in _wrapped_view
  response = view_func(request, *args, **kwargs)

File "project/virtualenv/lib/python2.7/site-packages/django/views/decorators/cache.py", line 52, in _wrapped_view_func
  response = view_func(request, *args, **kwargs)

File "project/virtualenv/lib/python2.7/site-packages/django/contrib/admin/sites.py", line 197, in inner
  return self.login(request)

File "project/virtualenv/lib/python2.7/site-packages/django/views/decorators/cache.py", line 52, in _wrapped_view_func
  response = view_func(request, *args, **kwargs)

File "project/virtualenv/lib/python2.7/site-packages/django/contrib/admin/sites.py", line 330, in login
  return login(request, **defaults)

File "project/virtualenv/lib/python2.7/site-packages/django/views/decorators/debug.py", line 75, in sensitive_post_parameters_wrapper
  return view(request, *args, **kwargs)

File "project/virtualenv/lib/python2.7/site-packages/django/utils/decorators.py", line 99, in _wrapped_view
  response = view_func(request, *args, **kwargs)

File "project/virtualenv/lib/python2.7/site-packages/django/views/decorators/cache.py", line 52, in _wrapped_view_func
  response = view_func(request, *args, **kwargs)

File "project/virtualenv/lib/python2.7/site-packages/django/contrib/auth/views.py", line 43, in login
  auth_login(request, form.get_user())

File "project/virtualenv/lib/python2.7/site-packages/django/contrib/auth/__init__.py", line 83, in login
  request.session.cycle_key()

File "project/virtualenv/lib/python2.7/site-packages/django/contrib/sessions/backends/base.py", line 277, in cycle_key
  self.create()

File "project/virtualenv/lib/python2.7/site-packages/django/contrib/sessions/backends/db.py", line 40, in create
  self.save(must_create=True)

File "project/virtualenv/lib/python2.7/site-packages/django/contrib/sessions/backends/db.py", line 62, in save
  with transaction.atomic(using=using):

File "project/virtualenv/lib/python2.7/site-packages/django/db/transaction.py", line 244, in __enter__
  "Your database backend doesn't behave properly when "

TransactionManagementError: Your database backend doesn't behave properly when autocommit is off. Turn it on before using 'atomic'.

我已经从MIDDLEWARE_CLASSES中删除了TransactionMiddleware,并将其替换为ATOMIC_REQUESTS = True。(即使我不执行此步骤,仍会出现相同的错误)

能有人解释一下这是什么原因吗?


你是否在一个被 @transaction 装饰的代码块中尝试使用一个使用原子保存的命令(例如 get_or_create())? - OldTinfoil
我只是使用Django的通用视图,并在south数据迁移中执行get_or_create。我没有明确地使用@transaction装饰任何视图,但我不确定Django是否会自动执行此操作。即便如此,在执行数据迁移时,Django仍然会抛出相同的错误。 - SunnySydeUp
你在South迁移中如何使用get_and_create()?我很确定South使用@transactions进行优化(如果没有,我会非常惊讶)。如果你用完整的扩展定义(即try/catch块)替换get_or_create(),那应该可以正常运行... - OldTinfoil
forwards 函数中,我会这样做:orm["auth.Group"].objects.get_or_create(name="blah")。等有机会了,我会尝试你的建议。 - SunnySydeUp
1
没关系,伙计。只要你有东西能够工作就好了;)你可能会引用数据库中还不存在的对象。 - OldTinfoil
显示剩余3条评论
5个回答

22

我在使用Django 1.6时,在sqlite3数据库中遇到了这个问题。以下是解决方案:

  1. django.middleware.transaction.TransactionMiddleware已被弃用。如果您的settings.py文件中没有此项配置,则不应该出现错误。

  2. 偶然发现,如果您在中间件列表中保留了django.middleware.transaction.TransactionMiddleware,则包含ATOMIC_REQUESTS:True可以解决此错误。

例如:

DATABASES = {
  'default': {
    'ENGINE': 'django.db.backends.sqlite3',
    'NAME': 'sqlite3-db',
    'ATOMIC_REQUESTS': True
  }
}

1
当您运行测试时,第二个解决方案是否有效? - SunnySydeUp
没有尝试,因为我选择了第一个解决方案。 - Overclocked
事务中间件已被弃用,推荐使用ATOMIC_REQUESTS。而且我在问题中已经说明我已经将其从中间件列表中删除了。 - SunnySydeUp
18
@Overclocked:我认为这个方法行不通,我没有TransactionMiddleware,并且无论是否使用ATOMIC_REQUESTS选项,我都会从sessions后端收到相同的错误信息。 - Wolph
谢谢,禁用原子请求有所帮助。 - alexche8
显示剩余2条评论

14

在我的forwards迁移中也遇到了同样的问题(有趣的是,在我的backwards迁移中没有出现),并且我的设置中没有TransactionMiddleware。 我的解决方法是避免使用get_or_create方法,而是更加详细地执行相同的操作。根据Django文档

try:
    obj = Person.objects.get(first_name='John', last_name='Lennon')
except Person.DoesNotExist:
    obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
    obj.save()

你可以按照以下方式创建自己的伪get_or_create方法:

def fake_get_or_create(model, *args, **kwargs):
    try:
        obj = model.objects.get(**kwargs)
    except model.DoesNotExist:
        obj = model(**kwargs)
        obj.save()
    return obj

您可以按照以下步骤使用

obj = fake_get_or_create(Person, first_name='John', last_name='Lennon')

使用South迁移升级到Django 1.6.5时,这个解决方案对我很有效。 - rhigdon
1
这是所发布问题的答案。 - mkoistinen

7

我在使用sqlite3时遇到了同样的问题。后来发现自己使用了transaction.commit_on_success。将其改为transaction.atomic()后,问题得到解决。


这是我在这里唯一有效的方法。谢谢! - Max

1
将这些添加到你的迁移中。
def forwards(self, orm):
    if connection.vendor == 'sqlite':
        set_autocommit(True)

它将为迁移设置自动提交为true :)


1
我认为错误是由于Sqlite3的限制造成的。为了解决这个问题,我不得不从Sqlite3切换到更强大的数据库引擎,如postgrsql_psycopg2
抛出错误的代码(transaction.py:244)在注释中提供了线索:
        if not connection.get_autocommit():
            # Some database adapters (namely sqlite3) don't handle
            # transactions and savepoints properly when autocommit is off.
            # Turning autocommit back on isn't an option; it would trigger
            # a premature commit. Give up if that happens.
            if connection.features.autocommits_when_autocommit_is_off:
                raise TransactionManagementError(
                    "Your database backend doesn't behave properly when "
                    "autocommit is off. Turn it on before using 'atomic'.")

查看最新的南方文档(0.8.4)可以更清楚地了解有关Sqlite3的问题:http://south.readthedocs.org/en/latest/databaseapi.html#database-specific-issues

SQLite几乎不支持原生模式更改,但South有解决方法,允许删除/更改列。但是,唯一索引仍然不受支持; South将默默忽略任何此类命令。

在我的情况下,我的模型中有唯一索引,似乎不受支持。

2
谢谢您的建议。但不幸的是,目前我还被迫使用sqlite。 - SunnySydeUp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接