我与django的用户和UserInfo有一对一的字段。我想订阅用户模型上的post_save回调函数,以便我可以保存UserInfo。
@receiver(post_save, sender=User)
def saveUserAndInfo(sender, instance, **kwargs):
user = instance
try:
user.user_info.save()
except:
info = UserInfo()
info.user = user
info.save()
然而,当我尝试这样做时,我得到TransactionManagementError
。我假设因为用户模型还没有完成保存,我正在尝试读取id以将其保存到user_info。任何人都知道如何正确地做到这一点?
第二个问题。我想在创建用户后立即将UserInfo实例附加到用户。所以在post_init上我尝试创建一个UserInfo实例并将其分配给用户实例,但它不起作用,因为尚未为用户分配pk。我假设我只需要等到post_save(或更高版本)来创建此实例。这是唯一的方法吗?
回溯:
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
114. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/contrib/admin/options.py" in wrapper
430. return self.admin_site.admin_view(view)(*args, **kwargs)
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapped_view
99. response = view_func(request, *args, **kwargs)
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
52. response = view_func(request, *args, **kwargs)
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/contrib/admin/sites.py" in inner
198. return view(request, *args, **kwargs)
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapper
29. return bound_func(*args, **kwargs)
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapped_view
99. response = view_func(request, *args, **kwargs)
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/utils/decorators.py" in bound_func
25. return func(self, *args2, **kwargs2)
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/db/transaction.py" in inner
339. return func(*args, **kwargs)
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/contrib/admin/options.py" in add_view
1129. self.save_model(request, new_object, form, False)
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/contrib/admin/options.py" in save_model
858. obj.save()
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/db/models/base.py" in save
545. force_update=force_update, update_fields=update_fields)
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/db/models/base.py" in save_base
582. update_fields=update_fields, raw=raw, using=using)
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/dispatch/dispatcher.py" in send
185. response = receiver(signal=self, sender=sender, **named)
File "/Users/croberts/lunchbox/userinfo/models.py" in saveUserAndInfo
83. info.save()
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/db/models/base.py" in save
545. force_update=force_update, update_fields=update_fields)
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/db/models/base.py" in save_base
573. updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/db/models/base.py" in _save_table
654. result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/db/models/base.py" in _do_insert
687. using=using, raw=raw)
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/db/models/manager.py" in _insert
232. return insert_query(self.model, objs, fields, **kwargs)
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/db/models/query.py" in insert_query
1511. return query.get_compiler(using=using).execute_sql(return_id)
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in execute_sql
898. cursor.execute(sql, params)
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/db/backends/util.py" in execute
69. return super(CursorDebugWrapper, self).execute(sql, params)
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/db/backends/util.py" in execute
47. self.db.validate_no_broken_transaction()
File "/Users/croberts/.virtualenvs/lunchbox/lib/python2.7/site-packages/django/db/backends/__init__.py" in validate_no_broken_transaction
365. "An error occurred in the current transaction. You can't "
Exception Type: TransactionManagementError at /gov/auth/user/add/
Exception Value: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.
答案 0 :(得分:18)
该错误是由user.user_info.save()
行引发异常引起的,并且该事务被标记为已损坏(PostgreSQL强制回滚整个事务,或者在该事务中再执行任何查询之前存储的任何保存点)
发生错误时可以回滚事务:
from django.db import IntegrityError, transaction
@receiver(post_save, sender=User)
def saveUserAndInfo(sender, instance, **kwargs):
user = instance
try:
with transaction.atomic():
user.user_info.save()
except IntegrityError:
info = UserInfo()
info.user = user
info.save()
documentation中详细描述了这一点。
另外,请注意,捕获所有异常类型通常不是最好的主意,因为您可能会将您不期望的异常静音。