46

我在 django 中有一个扩展的 UserProfile 模型:

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

还有一个signals.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

所以这应该为每个注册的用户创建一个新的用户配置文件,对吧?但事实并非如此。当我尝试登录时,我总是收到“用户配置文件匹配查询不存在”错误,这意味着数据库条目不存在。

我应该说我使用 django-registration,它提供了 user_registered 信号。

重要应用程序的结构是,我有一个名为“用户”的应用程序,我有:models.py、signals.py、urls.py 和 views.py(以及其他一些在这里不重要的东西)。UserProfile 类在 models.py 中定义。

更新:我将 signals.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,现在我的 signals.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")
4

6 回答 6

31

您可以在用户上使用 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)
于 2009-12-15T23:02:30.670 回答
6

这对我有帮助: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")
于 2012-03-28T13:26:01.853 回答
6

您可以改为在首次访问每个用户时创建扩展配置文件:

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/

于 2011-05-01T23:00:44.750 回答
5

当你打电话时profile.setUser(),我认为你想传递instance而不是sender作为参数。

user_registered 信号的文档中sender指的是User类;instance是注册的实际用户对象。

于 2009-12-15T22:54:15.413 回答
1

根据我的最新研究,创建一个单独的文件(例如 singals.py)是行不通的。

你最好在你的models.py中直接将'create_profile'连接到'post_save',否则这段代码将不会被执行,因为它在一个单独的文件中并且没有人导入它。

我的最终代码供您参考:

# 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")
于 2017-07-19T01:48:11.823 回答
0

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)
于 2018-03-30T04:02:38.530 回答