如何将动态数据库名称传递给装饰器?
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)
的。