В Django, когда я вызываю User.objects.create_user (имя пользователя, адрес электронной почты, пароль) - почему post_save вызывается дважды? - PullRequest
2 голосов
/ 19 января 2012

В views.py у меня есть следующий вид, который вызывается при регистрации новой учетной записи пользователя.Все, что он делает, это получает имя пользователя, адрес электронной почты и пароль из запроса, а затем пытается создать пользователя с этими учетными данными.В приведенном ниже коде печатается «A», а «B» - нет, потому что происходит сбой:

views.py

def register(request):
    if request.method == 'POST':
        query_dict = request.POST
        username = query_dict['username']
        email = query_dict['user_email']
        password = query_dict['password']
        role = query_dict['role']
        print "A"
        user = User.objects.create_user(username, email, password)
        # the handler is called here and creates the user profile
        print "B"
        user = authenticate(username=username, password=password)
        user_profile = user.get_profile()
        user_profile.role = role
        user_profile.save()
        if user is not None and user.is_active:
            login(request, user)
            return HttpResponseRedirect("/")

В myapp/models.py У меня есть следующий код для обработчика.

'models.py`

post_save.connect(create_user_profile, sender=User)

def create_user_profile(sender, instance, created, **kwargs):
    print "created="+str(created)
    if created: # as opposed to being saved after being created earlier, I assume
        print "attempting to create a user profile for "+instance.username
        up = UserProfile.objects.create(user=instance)
        print "created a new UserProfile: <"+str(up)+">"

Когда я запускаю свое приложение, вывод на печать выглядит так:

A
created=True
attempting to create a user profile for john
created a new UserProfile: <john - >
created=True
attempting to create a user profile for john
~~~~CRASHES~~~~

За последние несколько дней я заметил, что во время моей разработки метод create_user_profile вызывался дважды при запуске User.objects.create_user(username, email, password)Я скопировал код обработчика прямо из документации, поэтому я уверен, что он правильный (https://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users). Я не знаю точно, откуда в коде django вызывается метод create_user_profile, но я предполагаю, что он устанавливаетcreated помечает значение true только в том случае, если метод сохранения, вызвавший обработчик, был вызван созданным объектом. За последние несколько дней этот код работал правильно, но внезапно сегодня во второй раз create_user_profileметод вызывается обработчиком, флаг created устанавливается в значение true, как это было в первый раз. Это приводит к падению моего приложения с IntegrityError, жалуясь на то, что оно не может создать два объекта с одинаковымпервичныйключ.

Итак, есть две вещи, которые я не понимаю.Первое: почему post_save происходит дважды, когда я звонил User.objects.create_user(username, email, password) только один раз;второе: почему флаг created внезапно перестал работать, как ожидалось?

Как я могу отладить это?

Спасибо

1 Ответ

7 голосов
/ 19 января 2012

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

Это может легко произойти, если вы импортируете один раз как

import myapp.models

и снова как

import myproject.myapp.models

Печать чего-либо на консоли в верхней части файла может дать вам представление о том, что происходит, или нет.

В любом случае, вы можете предотвратить многократную регистрацию обработчика сигнала, присвоив ему уникальный dispatch_uid. Django проверит на Signal.connect, чтобы увидеть, был ли обработчик уже зарегистрирован для того же отправителя с тем же UID, и не перерегистрирует его, если он имеет.

Измените код подключения сигнала на что-то вроде

post_save.connect(create_user_profile, sender=User, dispatch_uid='create_user_profile')

и посмотрите, поможет ли это

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...