django - tutorial - Crear un perfil de usuario extendido
email verification django (6)
Cuando llamas a profile.setUser()
, creo que quieres pasar la instance
lugar del sender
como parámetro.
De la documentación de la señal registrada por el usuario , el sender
refiere a la clase de User
; instance
es el objeto de usuario real que se registró.
Tengo un modelo de perfil de usuario extendido en django:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
#other things in that profile
Y un signals.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 perfil de usuario para cada usuario que se registre, verdad? Pero no es así Siempre obtengo errores de "La coincidencia de perfil de usuario no existe" cuando intento iniciar sesión, lo que significa que la entrada de la base de datos no está allí.
Debo decir que uso django-registration, que proporciona la señal user_registered.
La estructura de las aplicaciones importantes para esto es que tengo una aplicación llamada "usuarios", allí tengo: models.py, signals.py, urls.py y views.py (y algunas otras cosas que no deberían importar aquí ) La clase UserProfile se define en models.py.
Actualización : cambié el signal.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":
"column user_id no es único"
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_saveseemstobeemittedtwiceforeachsave
Tuve que agregar un dispatch_uid, ahora mi signal.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")
De acuerdo con mi última investigación, crear un archivo separado, por ejemplo, singals.py, no funciona.
Será mejor que conecte ''create_profile'' a ''post_save'' en su models.py directamente, de lo contrario, este fragmento de 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")
Esto me ayudó: primary_key = True
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")
Puede obtener el perfil extendido que se creará cuando se acceda 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
ref: http://www.codekoala.com/blog/2009/quick-django-tip-user-profiles/
Puedes 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)
Actualización para 2018:
Esta pregunta ha recogido muchas opiniones, tal vez es hora de una actualización.
Esta es la última versión de la última 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)