Создание расширенного профиля пользователя
У меня есть расширенная модель UserProfile в Django:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
#other things in that profile
И сигналы.
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
Мне пришлось добавить 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 ответов
Вы можете реализовать это, используя 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)
Редактировать:
Еще одно возможное решение, которое протестировано и работает (я использую его на своем сайте):
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)
Вы можете получить расширенный профиль, который будет создан при первом обращении к каждому пользователю:
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
ссылка: http://www.codekoala.com/blog/2009/quick-django-tip-user-profiles/
Это помогло мне: 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")
Когда вы звоните profile.setUser()
Я думаю ты хочешь пройти instance
скорее, чем sender
в качестве параметра.
Из документации по сигналу user_registered, sender
относится к User
учебный класс; instance
фактический пользовательский объект, который был зарегистрирован.
Согласно моим последним исследованиям, создание отдельного файла, например, 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")
Обновление для 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)