Как предотвратить конфликт между приборами с сигнальным кодом django post_save? - PullRequest
46 голосов
/ 17 августа 2010

В моем приложении я хочу создавать записи в определенных таблицах, когда новый пользователь регистрируется.Например, я хочу создать профиль пользователя, который будет ссылаться на их компанию и некоторые другие записи для них.Я реализовал это с помощью сигнала post_save:

def callback_create_profile(sender, **kwargs):
    # check if we are creating a new User
    if kwargs.get('created', True):
        user = kwargs.get('instance')
        company = Company.objects.create(name="My Company")
        employee = Employee.objects.create(company=company, name_first=user.first_name, name_last=user.last_name)
        profile = UserProfile.objects.create(user=user, employee=employee, partner=partner)
# Register the callback
post_save.connect(callback_create_profile, sender=User, dispatch_uid="core.models")

Это хорошо работает при запуске.Я могу использовать администратора для создания нового пользователя, а остальные три таблицы также получают записи с разумным значением.(За исключением того, что сотрудник, так как user.first_name и user.last_name не заполняется в форме администратора при сохранении. Я до сих пор не понимаю, почему это делается так)

Проблемапришел, когда я запустил свой тестовый набор.До этого я создал несколько приборов для создания этих записей в таблицах.Теперь я получаю сообщение об ошибке:

IntegrityError: duplicate key value violates unique constraint "core_userprofile_user_id_key"

Я думаю, это потому, что я уже создал записи о компании, сотруднике и профиле в приборе с идентификатором "1", а теперь сигнал post_save пытается воссоздатьэто.

Мои вопросы: могу ли я отключить этот сигнал post_save при запуске приборов?Могу ли я определить, что я работаю как часть набора тестов, и не создавать эти записи?Должен ли я удалить эти записи из приборов сейчас (хотя сигнал устанавливает только значения по умолчанию, а не значения, которые я хочу проверить)?Почему код загрузки прибора не перезаписывает созданные записи?

Как люди это делают?

Ответы [ 4 ]

68 голосов
/ 17 августа 2010

Думаю, я нашел способ сделать это. В переданных вместе с сигналами параметрах «raw» есть параметр «raw», поэтому я могу заменить приведенный выше тест следующим:

if (kwargs.get('created', True) and not kwargs.get('raw', False)):

Raw используется при запуске loaddata. Это, кажется, делает трюк.

Здесь упоминается: http://code.djangoproject.com/ticket/13299

Было бы неплохо, если бы это было задокументировано: http://docs.djangoproject.com/en/1.2/ref/signals/#django.db.models.signals.post_save

17 голосов
/ 10 июля 2012

Это старый вопрос, но наиболее простым решением, которое я нашел, является использование «сырого» аргумента, передаваемого данными загрузки, и декорирование функций слушателя, например:

from functools import wraps


def disable_for_loaddata(signal_handler):
    @wraps(signal_handler)
    def wrapper(*args, **kwargs):
        if kwargs['raw']:
            print "Skipping signal for %s %s" % (args, kwargs)
            return
        signal_handler(*args, **kwargs)
    return wrapper

а затем

@disable_for_loaddata
def callback_create_profile(sender, **kwargs):
    # check if we are creating a new User
    ...
10 голосов
/ 10 февраля 2014

Простое решение, добавьте это в начало вашей функции post_save:

if kwargs.get('raw', False):
    return False

Это приведет к выходу этой функции при загрузке прибора.*

1 голос
/ 17 августа 2010

Я столкнулся с подобной проблемой в одном из моих проектов.В моем случае сигналы также замедляли тесты.В итоге я отказался от сигналов в пользу переопределения метода Model.save().

В вашем случае, однако, я не думаю, что имеет смысл достигать этого путем переопределения любых методов save().В этом случае вы можете попробовать это.Предупреждение, я попробовал только один раз., похоже, работает, но не проходит тщательного тестирования.

  1. Создайте своего собственного бегуна .
  2. Перед загрузкой приборов, отключите функцию callback_create_profile от сигнала User class 'post_save.
  3. Дайте нагрузке приборам.
  4. Подключите функцию обратнок сигналу.
...