J'ai un modèle UserProfile étendu dans Django:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
#other things in that profile
Et un signal.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)
Je m'assure que le signal est enregistré en ayant ceci dans mon __init__.py
:
import signals
Cela devrait donc me créer un nouveau profil d’utilisateur pour chaque utilisateur qui s’inscrit, pas vrai? Mais ce n'est pas le cas. J'obtiens toujours des erreurs "La requête correspondante du profil utilisateur n'existe pas" lorsque j'essaie de me connecter, ce qui signifie que l'entrée de la base de données n'y est pas.
Je devrais dire que j'utilise Django-registration, qui fournit le signal user_registered.
La structure des applications importantes pour cela est que je possède une application appelée "utilisateurs", à savoir: models.py, signaux.py, urls.py et views.py (et quelques autres choses qui ne devraient pas avoir d'importance ici). ). La classe UserProfile est définie dans models.py.
Mise à jour: J'ai changé le signal.py en:
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)
Mais maintenant je reçois un "IntegrityError":
"la colonne user_id n'est pas unique"
Edit 2:
Je l'ai trouvé. On dirait que j'ai enregistré le signal deux fois. La solution de contournement pour cela est décrite ici: http://code.djangoproject.com/wiki/Signals#Helppost_saveseemstobeemittedtwiceforeachssave
Je devais ajouter un dispatch_uid, maintenant mon signaux.py ressemble à ceci et fonctionne:
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")
Vous pouvez l'implémenter en utilisant post_save sur l'utilisateur:
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)
Modifier:
Une autre solution possible, qui est testée et fonctionne (je l’utilise sur mon site):
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)
Cela m'a aidé: 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")
Vous pouvez obtenir le profil étendu à créer lors de la première utilisation pour chaque utilisateur:
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])
puis utiliser
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/
Lorsque vous appelez profile.setUser()
, je pense que vous souhaitez passer instance
au lieu de sender
en tant que paramètre.
Dans la documentation du signal user_registered , sender
fait référence à la classe User
; instance
est l'objet utilisateur réel qui a été enregistré.
Selon mes dernières recherches, créer un fichier séparé, par exemple, singals.py, ne fonctionne pas.
Vous feriez mieux de connecter 'create_profile' à 'post_save' dans votre fichier models.py directement, sinon ce morceau de code ne sera pas exécuté car il est dans un fichier séparé et personne ne l'importe.
Mon code final pour votre référence:
# 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")
Mise à jour pour 2018:
Cette question a recueilli beaucoup de points de vue, il est peut-être temps de faire une mise à jour.
Ceci est la dernière version pour le dernier 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)