Pregunta

Tengo un modelo de usuario de usuario extendido en Django:

class UserProfile(models.Model):
  user = models.ForeignKey(User, unique=True)
  #other things in that profile

Y un señales.py:

from registration.signals import user_registered
from models import UserProfile
from django.contrib.auth.models import User

def createUserProfile(sender, instance, **kwargs):
  profile = users.models.UserProfile()
  profile.setUser(sender)
  profile.save()

user_registered.connect(createUserProfile, sender=User)

Me aseguro de que la señal se registre teniendo esto en mi __init__.py:

import signals

Entonces eso debería crearme un nuevo usuario de usuario para cada usuario que se registre, ¿verdad? Pero no lo hace. Siempre recibo errores de "consulta de coincidencia de usuarios de usuarios" cuando intento iniciar sesión, lo que significa que la entrada de la base de datos no está allí.

Debo decir que uso la registro de django, que proporciona la señal de usuario de usuario.

La estructura de las aplicaciones importantes para esto es que tengo una aplicación llamada "usuarios", allí tengo: modelos.py, señales.py, urls.py y vers.py (y algunas otras cosas que no deberían importar aquí ). La clase UserProfile se define en Models.py.

Actualizar: Cambié las señales.py a:

from django.db.models.signals import post_save
from models import UserProfile
from django.contrib.auth.models import User

def create_profile(sender, **kw):
    user = kw["instance"]
    if kw["created"]:
        profile = UserProfile()
        profile.user = user
        profile.save()

post_save.connect(create_profile, sender=User)

Pero ahora obtengo un "IntegrityError":

"La columna user_id no es única"

Editar 2:

Lo encontré. Parece que de alguna manera registré la señal dos veces. La solución para esto se describe aquí: http://code.djangoproject.com/wiki/signals#helppost_saveseemstobeemitttwiceforeachsave

Tuve que agregar un disipph_uid, ahora mis señales.py se ve así y está funcionando:

from django.db.models.signals import post_save
from django.contrib.auth.models import User
from models import UserProfile
from django.db import models

def create_profile(sender, **kw):
    user = kw["instance"]
    if kw["created"]:
        profile = UserProfile(user=user)
        profile.save()

post_save.connect(create_profile, sender=User, dispatch_uid="users-profilecreation-signal")
¿Fue útil?

Solución

Puede implementarlo usando post_save en el usuario:

from django.db.models.signals import post_save
from models import UserProfile
from django.contrib.auth.models import User

def create_profile(sender, **kwargs):
    user = kwargs["instance"]
    if kwargs["created"]:
        profile = users.models.UserProfile()
        profile.setUser(sender)
        profile.save()

post_save.connect(create_profile, sender=User)

Editar:
Otra posible solución, que se prueba y funciona (la estoy usando en mi sitio):

from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
def create_profile(sender, **kwargs):
    user = kwargs["instance"]
    if kwargs["created"]:
        up = UserProfile(user=user, stuff=1, thing=2)
        up.save()
post_save.connect(create_profile, sender=User)

Otros consejos

Puede obtener el perfil extendido que se creará cuando se accede por primera vez para cada usuario en su lugar:

from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    additional_info_field = models.CharField(max_length=50)

User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])

Luego usa

from django.contrib.auth.models import User
user = User.objects.get(pk=1)
user.profile.additional_info_field

árbitro: http://www.codekoala.com/blog/2009/quick-django-tip-user-profiles/

Esto me ayudó: primario_key = verdadero

class UserProfile(models.Model):
    user = models.OneToOneField(User, unique=True, primary_key=True, related_name="user")
    phone = models.CharField(('phone'),max_length=30, blank=False, null=True)
    user_building = models.ManyToManyField(Building, blank=True)
    added_by = models.ForeignKey(User, blank=True, null=True, related_name="added")

Cuando usted llama profile.setUser(), Creo que quieres pasar instance más bien que sender como el parámetro.

Desde el Documentación de la señal de usuarios de usuarios, sender se refiere a User clase; instance es el objeto de usuario real que se registró.

Según mi última investigación, crear un archivo separado, por ejemplo, Singals.py, no funciona.

Será mejor que conecte 'create_profile' a 'post_save' en sus modelos.py directamente, de lo contrario, este código no se ejecutará ya que está en un archivo separado y nadie lo importa.

Mi código final para su referencia:

# models.py

# Here goes the definition of class UserProfile.
class UserProfile(models.Model):
    ...

# Use signal to automatically create user profile on user creation.

# Another implementation:
# def create_user_profile(sender, **kwargs):
#     user = kwargs["instance"]
#     if kwargs["created"]:
#         ...
def create_user_profile(sender, instance, created, **kwargs):
    """
    :param sender: Class User.
    :param instance: The user instance.
    """
    if created:
        # Seems the following also works:
        #   UserProfile.objects.create(user=instance)
        # TODO: Which is correct or better?
        profile = UserProfile(user=instance)
        profile.save()

post_save.connect(create_user_profile,
                  sender=User,
                  dispatch_uid="users-profilecreation-signal")

Actualización para 2018:

Esta pregunta ha recopilado muchas opiniones, tal vez es hora de una actualización.

Esta es la última versión para el último Django.

from django.dispatch import receiver
from django.db.models.signals import post_save
from django.conf import settings
from models import UserProfile

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_user_profile(sender, instance=None, created=False, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top