web-dev-qa-db-fra.com

Création d'un profil d'utilisateur étendu

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")
45
Kai

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)
29
Agos

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")
6
Vári Zorán

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/

6
Tim Abell

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é.

5
Ben James

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")
1
Adam Gu

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)
0
Oliver Ni