django TransactionManagementError when using signals

django, django-models, python

Solution

The error is caused by the `user.user_info.save()` line throwing an exception, and the transaction was flagged as broken (PostgreSQL enforces rolling back either the whole transaction, or to any savepoint stored before doing any more queries inside that transaction).

You can rollback the transaction when an error occurs:

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()

This is greatly described in the documentation.

Also, note that catching all exception types is not generally the best idea as you might silence exceptions you weren't expecting.

Problem

I have a one to one field with django's users and UserInfo. I want to subscribe to the post_save callback function on the user model so that I can then save the UserInfo as well. ``` @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() ``` However, I am getting a `TransactionManagementError` when I try to do this. I am assuming because the user model hasn't finished saving and I am trying to read the id to save it to the user_info. Anyone know how to do this properly? A second problem. I wanted to attach a UserInfo instance to a user as soon as the user was created. So on post_init I tried to create a UserInfo instance and assign it to the user instance but it doesn't work because the user hasn't been assigned a pk yet. I am assuming I just have to wait until post_save (or later) to create this instance. Is this the only way to do it? Traceback: ``` 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. ```

Original source

Related problems