如何将动态数据库名称传递给装饰器?

3 投票
1 回答
1085 浏览
提问于 2025-04-17 12:36

Django 有一个叫做 @transaction.commit_manually 的装饰器函数。我想给这个装饰器传一个参数,(using=db)。这个 db 是根据业务规则来决定的,不同的情况下会用不同的数据库。请问有什么好的方法可以把当前的数据库传给这个装饰器呢?我尝试使用了一个内部函数,像这样:

def func(db):
    stuff = _business logic_

    @transaction.commit_manually(using=db)
    def do_transaction(stuff):
        try:
            stuff.save(using=db)
        except:
            transaction.rollback()
        else:
            transaction.commit()

    do_transaction()

但是,这样做失败了。我用 pdb 调试时发现,内部块的错误是“没有在事务管理下”。我该如何解决这个问题呢?

pdb 得到的错误信息:

-> success = transactional_registration()
  /usr/local/lib/python2.7/dist-packages/django/db/transaction.py(338)_commit_manually()
-> return func(*args, **kw)
> /home/syrion/dev/registration.py(59)transactional_registration()
-> transaction.rollback()
  /usr/local/lib/python2.7/dist-packages/django/db/transaction.py(210)rollback()
-> set_clean(using=using)
  /usr/local/lib/python2.7/dist-packages/django/db/transaction.py(125)set_clean()
-> raise TransactionManagementError("This code isn't under transaction management"

编辑: 我自己解决了这个问题。内部函数的方案是可以正常工作的,但我需要在调用 rollback()commit() 时也加上一个使用的参数,也就是 transaction.commit(using=db)。我觉得这有点不直观,不过……

1 个回答

1

我在代码中经常使用这个,因为我对ORM(对象关系映射)要求很高。由于我不太喜欢装饰器的写法,所以我选择使用with语句。

def do_transaction(stuff, db):
    with transaction.commit_manually(using=db)
        try:
            stuff.save(using=db)
        except:
            transaction.rollback()
        else:
            transaction.commit(using=db)

这个应该可以正常工作。不过,我不确定在你的transaction.rollback()中是否需要加(using=db),你可以自己查一下。不过在transaction.commit(using=db)中是需要加(using=db)的。

撰写回答