Pergunta

Eu tenho um modelo estendido do UserProfile em Django:

class UserProfile(models.Model):
  user = models.ForeignKey(User, unique=True)
  #other things in that profile

E um sinals.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)

Eu certifico -me de que o sinal seja registrado por ter isso no meu __init__.py:

import signals

Portanto, isso deve me criar um novo usuário do usuário para todos os usuários que se registram, certo? Mas não. Eu sempre recebo erros "UserProfile correspondente à consulta não existe" quando tento fazer login, o que significa que a entrada do banco de dados não está lá.

Devo dizer que uso o registro de Django, que fornece o sinal user_registered.

A estrutura dos aplicativos importantes para isso é que tenho um aplicativo chamado "Usuários", lá tenho: models.py, sinals.py, urls.py e views.py (e algumas outras coisas que não devem importar aqui ). A classe UserProfile é definida em models.py.

Atualizar: Eu mudei o sinals.py para:

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)

Mas agora eu recebo um "IntegrityError":

"Coluna User_id não é única"

Editar 2:

Eu encontrei. Parece que de alguma forma eu registrei o sinal duas vezes. A solução alternativa para isso é descrita aqui: http://code.djangoproject.com/wiki/signals#helppost_saveseemstobeMittitTwiceForEachSave

Eu tive que adicionar um despacho_uid, agora meus sinais.py se parecem com isso e 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")
Foi útil?

Solução

Você pode implementá -lo usando post_save no usuário:

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:
Outra solução possível, que é testada e funciona (estou usando -a no meu 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)

Outras dicas

Você pode obter o perfil estendido a ser criado quando acessado pela primeira vez para cada usuário:

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])

Em seguida, use

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/

Isso me ajudou: 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")

Quando Você ligar profile.setUser(), Acho que você quer passar instance ao invés de sender como o parâmetro.

De Documentação do sinal User_registered, sender refere-se a User classe; instance é o objeto de usuário real que foi registrado.

De acordo com minha pesquisa mais recente, a criação de um arquivo separado, por exemplo, Singals.Py, não funciona.

É melhor você conectar 'create_profile' a 'post_save' em seus modelos.py diretamente, caso contrário, esse código não será executado, pois está em um arquivo separado e ninguém o importa.

Meu código final para sua referência:

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

Atualização para 2018:

Esta pergunta coletou muitas visualizações, talvez seja hora de uma atualização.

Esta é a versão mais recente do mais recente 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)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top