Создание расширенного профиля пользователя - PullRequest
46 голосов
/ 15 декабря 2009

У меня расширенная модель UserProfile в django:

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

И сигналы.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)

Я проверяю, зарегистрирован ли сигнал, указав это в моем __init__.py:

import signals

Так что это должно создать мне новый UserProfile для каждого зарегистрированного пользователя, верно? Но это не так. Я всегда получаю сообщение об ошибке «Запрос соответствия UserProfile не существует», когда я пытаюсь войти в систему, что означает, что запись базы данных отсутствует.

Я должен сказать, что я использую django-registration, который предоставляет сигнал user_registered.

Структура важных приложений для этого такова, что у меня есть одно приложение под названием «пользователи», там у меня есть: models.py, signal.py, urls.py и views.py (и некоторые другие вещи, которые не должны ' не имеет значения здесь). Класс UserProfile определен в models.py.

Обновление : Я изменил signal.py на:

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)

Но теперь я получаю "IntegrityError":

"столбец user_id не уникален"

Редактировать 2:

Я нашел это. Похоже, я как-то зарегистрировал сигнал дважды. Обходной путь для этого описан здесь: http://code.djangoproject.com/wiki/Signals#Helppost_saveseemstobeemittedtwiceforeachsave

Мне пришлось добавить dispatch_uid, теперь мой signal.py выглядит так и работает:

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

Ответы [ 6 ]

30 голосов
/ 16 декабря 2009

Вы можете реализовать это, используя post_save для пользователя:

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:
Другое возможное решение, которое протестировано и работает (я использую его на своем сайте):

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)
6 голосов
/ 28 марта 2012

Это помогло мне: 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 голосов
/ 02 мая 2011

Вы можете получить расширенный профиль, который будет создан при первом доступе для каждого пользователя:

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

затем используйте

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/

5 голосов
/ 16 декабря 2009

Когда вы вызываете profile.setUser(), я думаю, что вы хотите передать instance вместо sender в качестве параметра.

Из документации зарегистрированного пользователем сигнала , sender относится к классу User; instance - это фактический зарегистрированный объект пользователя.

1 голос
/ 19 июля 2017

Согласно моим последним исследованиям, создание отдельного файла, например, singals.py, не работает.

Вам лучше подключить 'create_profile' к 'post_save' в вашем файле models.py напрямую, иначе этот фрагмент кода не будет выполнен, поскольку он находится в отдельном файле и никто его не импортирует.

Мой окончательный код для вашей справки:

# 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")
0 голосов
/ 30 марта 2018

Обновление на 2018 год:

Этот вопрос собрал много просмотров, возможно, пришло время для обновления.

Это последняя версия для последней версии 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)
...