2013-11-21 2 views
10

У меня есть одно к одному поле с пользователями django и UserInfo. Я хочу подписаться на функцию обратного вызова post_save в пользовательской модели, чтобы затем я мог сохранить UserInfo.django TransactionManagementError при использовании сигналов

@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, когда я пытаюсь сделать это. Я предполагаю, что пользовательская модель не закончила сохранение, и я пытаюсь прочитать идентификатор, чтобы сохранить его в user_info. Кто-нибудь знает, как это сделать правильно?

Вторая проблема. Я хотел бы прикрепить экземпляр UserInfo к пользователю, как только пользователь будет создан. Поэтому в post_init я попытался создать экземпляр UserInfo и назначить его экземпляру пользователя, но он не работает, потому что пользователю еще не присвоен pk. Я предполагаю, что мне просто нужно подождать, пока post_save (или позже) не создаст этот экземпляр. Это единственный способ сделать это?

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. 
+0

Post full traceback, пожалуйста. –

+0

Только что обновлено с трассировкой. –

+0

Попробуйте поместить 'sp = transaction.savepoint()' before' try: except: ',' ​​transaction.savepoint_rollback (sp) 'right after' except:' и before'info = UserInfo() 'и' transaction.savepoint_commit (sp) 'к вашему' finally: 'close of' try: except: '. –

ответ

17

ошибка вызвана 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.

Кроме того, обратите внимание, что вылавливание всех типов исключений обычно не является лучшей идеей, так как вы можете отключить исключения, которых вы не ожидали.

+0

Это имеет смысл и работает, за исключением случаев, когда я пытаюсь сделать новых пользователей с панели администратора. У меня есть User и UserInfo, сгруппированные вместе, используя встроенные строки, и я думаю, что он пытается сохранить вещь одновременно, поэтому он дает мне IntegrityError at/loginView/ . Column_ user_id не уникален. –

+0

@ChaseRoberts, проверьте [этот ответ] (http://stackoverflow.com/a/6117457/1338158). Это решает проблему. –

+0

Являются ли транзакции save() не атомными? С 10k запросов в минуту это было бы большим изменением для моей модели –

Смежные вопросы