Django事务管理块在检查权限时以待定的COMMIT/ROLLBACK结束

0 投票
3 回答
2086 浏览
提问于 2025-04-17 12:57

每当我在一个视图中使用了 @transaction.commit_manually 装饰器的模板里检查权限时,就会出现这个错误 Transaction managed block ended with pending COMMIT/ROLLBACK

模板内容:

<!-- html stuff -->
{% if perms.myApp.add_table1 %}
    {# show html elements #}
{% endif %}

一旦我去掉了权限检查的条件,就没有任何错误了。与权限无关的 if 条件是可以正常工作的,比如 {% if user.is_superuser %}{% endif %}

更新:即使权限检查不在视图渲染的模板上,而是在从中扩展的模板上,仍然会出现这个错误。

例如,在 nav_bar.html 中检查权限,而视图渲染的是扩展自 nav_bar.html 的 expense.html,也会导致同样的错误。

view.py 文件:

@transaction.commit_manually
def add_expense(request):
    # do stuff here

我尝试去掉这个装饰器,结果没有任何异常,所有功能都正常。但一旦我加上这个装饰器,就会出现错误。

urls.py 文件:

# other stuff omitted
(r'^myApp/expenses/add/$', add_expense),

更新 #2:

当用户是超级用户时,也没有问题。我认为这是因为超级用户不需要检查权限,所以不会出错。

我还附上了代码:

@login_required()
@transaction.commit_manually
def add_expense(request):

    request.session.set_expiry(1800)

    if request.method == 'POST':
        form_input = AddExpense(request.POST)

        if form_input.is_valid():
            try:
            # after validation data is cleaned
                cd = form_input.cleaned_data
                # cleaned data is a dictionary
                input_date = date.today()
                user = request.user.username


                new_record = table1.objects.create(
                    amount = cd['amount'],
                    date = cd['date_of_expense'],
                    username = user
                    )
                new_record.save()
                transaction.commit()
                return render_to_response('forms/add_expense_success.html', context_instance=RequestContext(request))
            except Exception, e:
                pass
                transaction.rollback()
                return HttpResponse(None)
        else:

            return render_to_response('forms/add_expense.html', {'form': form_input},
                              context_instance=RequestContext(request))
    else:
        # loading this gives error, not sure the top part
        form = AddExpense()
        return render_to_response('forms/add_expense.html', {'form': form, 'page_title': '新增支出'},
                      context_instance=RequestContext(request))

3 个回答

0

我在尝试减少访问用户的权限时遇到了这个错误信息。

  • 使用的是 postgresql 9.1
  • python 版本是 2.7.3
  • django 版本是 1.3.1

如果以超级用户(管理员角色)身份运行,就没有任何问题;但如果以普通用户(用户角色)身份运行,就会出现错误。

这个用户在所有与 django 相关的表以及数据库和模式上都有所有权限(甚至包括授予权限),但仍然会出现错误。

这可能是什么原因呢?到目前为止,我调试发现,缺少的只是超级用户的权限,除此之外,超级用户和普通用户的权限是一样的。

代码:

@login_required
@transaction.commit_manually
def sipuser_add(request, extension_id):
    member = members.objects.get(nickname=request.user.username)
    extension = extensions.objects.get(id=extension_id)
    nickname = request.user.username
    if extension.id_members.nickname == member.nickname:
        from django.db import connection
        cursor = connection.cursor()
        secret = pwgen()
        cursor.execute("SELECT func_create_sipuser('%s','%s',%s)" % (nickname, secret, extension_id) )
        ret = cursor.fetchone()
        logger.debug("created extension_id: %s - stored procedure 'func_create_sipuser' returned: %s" % (extension_id, ret) )
        pin = 1234
        timeout = 15
        cursor.execute("SELECT func_create_voicemail_from_phonenumberid(%s,'%s',%s)" % (extension_id, pin, timeout) )
        ret = cursor.fetchone()
        logger.debug("created voicemail for extension_id %s - stored procedure 'func_create_voicemail' returned: %s" % (extension_id, ret) )
        cursor.close() # is this needed and/or on the right position called?
        connection.commit()
    return HttpResponseRedirect('/extensions/')
0

这是因为 context_instance=RequestContext(request) 引起的。

下面是 @Marcin 提供的解决方案。

Django 事务管理块结束时有待处理的提交/回滚

0

我想确认一下,错误信息的意思是,你是在使用Postgres,对吧?

如果是这样,我有一个建议:在你上面提到的# do stuff here这部分代码里,我敢打赌你在读取数据后没有手动提交,即使在写入数据后有提交。

从Django 1.3开始,读取数据的事务管理也会被算作脏数据,不仅仅是写入数据,所以你在读取后也需要调用commit()

想了解更多细节,可以查看发布说明

撰写回答