【问题标题】:Creating a extended user profile创建扩展用户配置文件
【发布时间】:2010-12-26 23:47:19
【问题描述】:

我在 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

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

我应该说我使用 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")

【问题讨论】:

  • 你能发布你的 django 应用程序的结构吗?我很好奇你代码中的几行,比如profile=user.models.UserProfile()——你有一个名为“用户”的模块吗? UserProfile() 位于何处。
  • 是用户,我不知道那个错字是怎么进来的,但问题是一样的。我想知道为什么 python 没有为拼写错误的路径抛出错误。
  • 感谢这个解决方案,我是 django 的新手,我不知道如何保存有关用户配置文件的其他数据。我看到您只是将用户保存在模型 UserProfile 中,但是如何从注册表单中保存其他人的数据(使用您的信号.py)?谢谢(对不起英语)

标签: django django-registration


【解决方案1】:

您可以在用户上使用 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)

【讨论】:

  • 必须是“profile.setUser(user)”,我想。但后来我得到“列 user_id 不是唯一的”。对此有什么想法吗?
  • 我为我的答案添加了另一个可能的解决方案,请查看。
  • 我得到“列 user_id 不是唯一的”,你能告诉我你的 UserProfile 模型吗?也许我的 ForeignKey() 有问题。
  • 让它工作。如果您对解决方案感兴趣,请查看我的初始帖子。
  • @Agos 描述如何在create_profile 中获取stuffthing 的值会很有帮助。
【解决方案2】:

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

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/

【讨论】:

    【解决方案3】:

    这对我有帮助: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")
    

    【讨论】:

    【解决方案4】:

    当你调用profile.setUser()时,我想你想传递instance而不是sender作为参数。

    documentation of the user_registered signalsender指的是User类; instance 是实际注册的用户对象。

    【讨论】:

      【解决方案5】:

      根据我的最新研究,创建一个单独的文件(例如 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")
      

      【讨论】:

        【解决方案6】:

        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 年,django >=1.11)它应该始终是:sender=get_user_model()docs.djangoproject.com/en/2.0/topics/auth/customizing/…
        • 应该 UserProfile.objects.create(user=instance) 而不是 UserProfile.objects.create(user=instance, **kwargs)
        • @theeastcoastwest 不。 **kwargs 与信号本身有关,它不包含您在创建配置文件时想要使用的任何数据。实际上,您只是想创建一个干净的 UserProfile 模型,而不是以任何方式更改它。
        • 我是否可以阅读有关使用信号创建相关对象(例如在这种情况下为 UserProfile)与使用模型管理器的资料?他们的方法和最佳实践有点推荐的优点和缺点?谢谢。
        猜你喜欢
        • 2023-03-23
        • 1970-01-01
        • 2012-04-30
        • 2021-09-12
        • 1970-01-01
        • 2011-02-19
        • 2021-12-30
        • 2012-03-11
        • 2015-07-08
        相关资源
        最近更新 更多