2010-05-11 18 views
10

He extendido el modelo de usuario de Django utilizando un perfil de usuario personalizado llamado UserExtension. Está relacionado con el usuario a través de una relación ForeignKey única, que me permite editarlo en el administrador en una forma en línea. estoy usando una señal para crear un nuevo perfil para cada nuevo usuario:Django: UserProfile con clave externa única en Django Admin

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) 

(tal como se describe aquí, por ejemplo: Extending the User model with custom fields in Django) El problema es que, si se crea un nuevo usuario a través de la administración, Obtengo una IntegritiyError al guardar "la columna user_id no es única". Parece que la señal no se llama dos veces, pero supongo que el administrador está tratando de guardar el perfil DESPUÉS? ¡Pero necesito la señal de creación si creo un nuevo usuario en otras partes del sistema!

+0

¿Podemos ver su gestor get_or_create? – Brant

+0

¡Es el administrador predeterminado de django! –

Respuesta

15

Es normal que Django crear la instancia de administración después, como el ahorro consta siempre de algo como esto:

  1. Crear objeto Usuario
  2. Crear objeto de perfil (no puede ser antes porque apunta a un usuario).

Al guardar el objeto Usuario, el django ORM no puede saber que el objeto de crear el perfil vendrá después de él para que no retrase la señal post_save de ninguna manera (ni siquiera tiene sentido).

La mejor manera de manejar esto (en mi humilde opinión) si desea mantener la señal post_save, consiste en redefinir el método save de UserExtension a algo como esto:

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) 

en cuenta que esto obligará cada inserción que apunta al mismo usuario como un objeto existente para convertirse en una actualización, este puede ser un comportamiento inesperado para otras partes del código.

+0

Anular el método de guardado predeterminado del modelo me parece una idea buena y fácil, ¡tendré que comprobar si funciona para mí en todos los casos de uso! Creo que "existing = UserExtension.objects.all(). Get (user = self.user)" puede ser "existing = UserExtension.objects.get (user = self.user)", o tenías algo especial en mente ¿con ese? :) ¡Gracias! –

+0

Nada especial, no necesitas '.all()' hasta donde yo sé. No estoy seguro de por qué lo agregué – KillianDS

Cuestiones relacionadas