46 votes

Création d'un profil 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 plaçant ceci dans mon fichier __init__.py :

import signals

Cela devrait donc me permettre de créer un nouveau UserProfile pour chaque utilisateur qui s'inscrit, non ? Mais ce n'est pas le cas. Je reçois toujours l'erreur "UserProfile matching query does not exist" lorsque j'essaie de me connecter, ce qui signifie que l'entrée dans la base de données n'existe pas.

Je dois dire que j'utilise django-registration, qui fournit le signal user_registered.

La structure des applications importantes pour cela est la suivante : j'ai une application appelée "users", où j'ai : models.py, signals.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 signals.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é. Il semble 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_saveseemstobeemittedtwiceforeachsave

J'ai dû ajouter un dispatch_uid, maintenant mon signals.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")

0 votes

Pourriez-vous afficher la structure de votre application django. Je suis curieux au sujet de quelques lignes dans votre code comme profile=user.models.UserProfile() - Avez-vous un module nommé 'user' ? Où se trouve UserProfile() ?

0 votes

Ce sont des utilisateurs, je ne sais pas comment cette coquille s'est retrouvée là, mais le problème est le même. Je me demande pourquoi python n'a pas lancé une erreur pour le chemin mal orthographié.

0 votes

Je vois que vous enregistrez simplement l'utilisateur dans le modèle UserProfile, mais comment puis-je enregistrer les données des autres (en utilisant vos signaux.py) à partir du formulaire d'enregistrement ? Merci (désolé pour l'anglais)

31voto

Agos Points 3858

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)

Edit :
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)

2 votes

Doit être "profile.setUser(user)", je pense. Mais ensuite j'obtiens "column user_id is not unique". Avez-vous une idée de ce qui se passe ?

0 votes

J'ai ajouté une autre solution possible à ma réponse, regardez-la.

0 votes

J'obtiens "column user_id is not unique", pouvez-vous me montrer votre modèle UserProfile ? Peut-être que j'ai fait une erreur avec la fonction ForeignKey().

6voto

Vári Zorán Points 51

Ceci 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")

3 votes

Primary_key=True implique null=False et unique=True. docs.djangoproject.com/fr/dev/ref/models/fields

6voto

Tim Abell Points 2301

Vous pouvez faire en sorte que le profil étendu soit créé lors du premier accès 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/

5voto

Ben James Points 41165

Lorsque vous appelez profile.setUser() Je pense que vous voulez passer instance plutôt que sender comme paramètre.

De la documentation du signal user_registered , sender fait référence à la User classe ; instance est l'objet utilisateur réel qui a été enregistré.

1voto

Adam Gu Points 96

D'après mes dernières recherches, la création d'un fichier séparé, par exemple singals.py, ne fonctionne pas.

Il est préférable de connecter 'create_profile' à 'post_save' dans votre fichier models.py directement, sinon ce morceau de code ne sera pas exécuté puisqu'il se trouve dans un fichier séparé et que 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")

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X