Django: профиль пользователя с уникальным внешним ключом в администраторе Django

Я расширил модель пользователя Django, используя собственный профиль пользователя с именем UserExtension. Он связан с пользователем через уникальное отношение ForeignKey, которое позволяет мне редактировать его в админке во встроенной форме! Я использую сигнал для создания нового профиля для каждого нового пользователя:

def create_user_profile(sender, instance, created, **kwargs):  
    if created:
        try:  
            profile, created = UserExtension.objects.get_or_create(user=instance)
        except:
            pass  

post_save.connect(create_user_profile, sender=User) 

(как описано здесь, например: Расширение модели пользователя с помощью настраиваемых полей в Django) Проблема в том, что если я создаю нового пользователя через администратора, я получаю IntegritiyError при сохранении «столбец user_id не уникален». Не похоже, что сигнал вызывается дважды, но я предполагаю, что администратор пытается сохранить профиль ПОСЛЕ? Но мне нужно создание через сигнал, если я создаю нового пользователя в других частях системы!


person Bernhard Vallant    schedule 11.05.2010    source источник
comment
Можем ли мы увидеть вашего менеджера get_or_create?   -  person Brant    schedule 11.05.2010
comment
Это менеджер django по умолчанию!   -  person Bernhard Vallant    schedule 12.05.2010


Ответы (1)


Это нормально, что django впоследствии создаст экземпляр администратора, так как сохранение всегда состоит из чего-то вроде этого:

  1. Создать объект пользователя
  2. Создать объект профиля (не может быть раньше, потому что он указывает на пользователя).

При сохранении объекта пользователя django ORM не может знать, что объект создания профиля появится после него, поэтому он никоим образом не будет задерживать сигнал post_save (даже не имеет смысла).

Лучший способ справиться с этим (имхо), если вы хотите сохранить сигнал post_save, — переопределить метод сохранения UserExtension примерно так:

def save(self, *args, **kwargs):
    try:
        existing = UserExtension.objects.get(user=self.user)
        self.id = existing.id #force update instead of insert
    except UserExtension.DoesNotExist:
        pass 
    models.Model.save(self, *args, **kwargs)

Обратите внимание, что это заставляет каждую вставку, которая указывает на того же пользователя, что и существующий объект, становиться обновлением, это может быть неожиданным поведением для других частей кода.

person KillianDS    schedule 11.05.2010
comment
Переопределение метода сохранения модели по умолчанию кажется мне хорошей и простой идеей, нужно будет проверить, работает ли он для меня во всех случаях использования! Я думаю, что уже существующий = UserExtension.objects.all().get(user=self.user) может быть уже существующим = UserExtension.objects.get(user=self.user), или вы имели в виду что-то особенное? :) Спасибо! - person Bernhard Vallant; 12.05.2010
comment
Ничего особенного, насколько я знаю, .all() не нужен. Я не уверен, почему я добавил это - person KillianDS; 12.05.2010