Création d'un profil utilisateur étendu
-
19-09-2019 - |
Question
J'ai un modèle UserProfile étendu à Django:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
#other things in that profile
Et 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)
Je m'assure que le signal est enregistré en ayant cela dans mon __init__.py
:
import signals
Cela devrait donc me créer un nouveau utilisateur pour chaque utilisateur qui enregistre, non? Mais ce n'est pas le cas. J'obtiens toujours des erreurs "UserProfile Matching Exist n'existe pas" lorsque j'essaie de me connecter, ce qui signifie que l'entrée de la base de données n'est pas là.
Je dois dire que j'utilise un inscription Django, qui fournit le signal User_Register.
La structure des applications importantes pour cela est que j'ai une application appelée "utilisateurs", là j'ai: modèles.py, signals.py, urls.py et vues.py (et d'autres choses qui ne devraient pas avoir d'importance ici ). La classe UserProfile est définie dans Models.py.
Mise à jour: J'ai changé les signaux.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 une "EnergityError":
"Column 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 est décrite ici: http://code.djangoproject.com/wiki/signals#helpost_saveseemstobemittetswiceforeachsave
J'ai dû ajouter un Dispatch_Uid, maintenant mes signaux.py ressemble à ceci et fonctionnent:
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")
La solution
Vous pouvez l'implémenter à l'aide de 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)
Éditer:
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)
Autres conseils
Vous pouvez obtenir le profil étendu à créer lors de la première fois pour la première fois 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
Réf: http://www.codekoala.com/blog/2009/quick-django-tip-user-profiles/
Cela m'a aidé: primaire_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")
Quand vous appelez profile.setUser()
, Je pense que tu veux passer instance
plutôt que sender
comme le paramètre.
Du Documentation du signal User_Register, sender
se réfère à la User
classer; instance
est l'objet utilisateur réel qui a été enregistré.
Selon mes dernières recherches, la création d'un fichier séparé, EG, Singals.py, ne fonctionne pas.
Vous feriez mieux de connecter 'create_profile' à 'post_save' dans vos modèles.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 vues, il est peut-être temps pour une mise à jour.
Il s'agit de la dernière version du 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)