【问题标题】:RelatedObjectDoesNotExist: User has no userprofileRelatedObjectDoesNotExist:用户没有用户配置文件
【发布时间】:2016-07-18 23:41:09
【问题描述】:

所以我使用score 字段扩展了我的用户,如下所示:

models.py:

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    score = models.IntegerField(default=0);

这似乎与recommended way 类似。

然后我尝试在我的视图中访问用户的userprofile

views.py:

player = request.user.userprofile

这似乎也与推荐的方式一致,但这就是我得到错误的地方:

RelatedObjectDoesNotExist
User has no userprofile.

如果我将 userprofile 更改为其他内容,我会收到另一个错误:

AttributeError
'User' object has no attribute 'flowerpot'

当我尝试以下代码时:

print request.user
print UserProfile.objects.all()

我得到控制台输出:

post_test1
[]

编辑
我有两个超级用户,扩展用户之前创建的七个用户,扩展用户后创建的一个用户 (post_test1)。


编辑 2

很明显,我需要创建一个 post_save 处理程序,该处理程序在创建用户对象时创建一个新的配置文件。

当我阅读它时,这似乎很简单,转到链接到的page,它是 Django 发送的所有信号的列表。我查了一下post_save,它说:

类似于 pre_save,但在 save() 方法结束时发送。

好的,所以我查了一下pre_save,它说:

这是在模型的 save() 方法开始时发送的。

我是这样解释的:当我创建用户时(在我的views.py 中),应该调用save() 方法,直到现在还没有这种情况,然后是post_save应该发送(?),这将在创建用户对象时创建一个新的配置文件!

所以现在我准备开始查看示例,所以我谷歌:

django post save example
Here 看起来我应该添加一些看起来像装饰器的东西@receiver(post_save, ...
Here 看起来我应该更改多个文件并编写一个信号定义?
This one 似乎也暗示了多个文件(包括一个signals.py

它看起来比我最初想象的要多得多。这里的任何人都可以解释我如何做到这一点,或者向我展示一些关于信号如何工作的好资源吗?

现在我的create_user 视图如下所示:

def create_user(request):
    if request.method == "POST":
        form = UserCreationForm(request.POST)
        if form.is_valid():
            username = form.cleaned_data["username"]
            password = form.cleaned_data["password1"]
            new_user = User.objects.create_user(username=username, password=password)
            return redirect('play')
    else:
        form = UserCreationForm()

    return render(request, 'antonymapp/create_user.html', {'form': form})

我应该在返回之前致电new_user.save() 吗?如果是的话,为什么它一直工作到现在?我在测试这个视图时创建了一堆用户。看起来这里的某个地方也应该添加post_save.connect(create_profile, sender=User)

【问题讨论】:

  • RelatedObjectDoesNotExist 表示没有与userprofile 相关的request.user,这很明显,不是吗?
  • 我使用用户配置文件扩展了用户,但仍然没有与请求用户相关的用户配置文件。所以,是的,你是对的。这显然是我在这里要问的问题。
  • 您是否在设置文件中设置了用户配置文件?例如,如果您的应用名称是基础名称,那么您需要将其添加到您的设置文件中。 AUTH_PROFILE_MODULE = 'base.UserProfile'

标签: python django django-authentication


【解决方案1】:

你必须先为用户创建一个userprofile

profile = UserProfile.objects.create(user=request.user)

在您的views.py 中,您可以使用get_or_create,以便在用户没有userprofile 时为该用户创建一个。

player, created = UserProfile.objects.get_or_create(user=request.user)

更新:要在每次创建新用户时自动创建用户配置文件,请使用信号。

myapp/signals.py 中执行以下操作:

@receiver(post_save, sender=User, dispatch_uid='save_new_user_profile')
def save_profile(sender, instance, created, **kwargs):
    user = instance
    if created:
        profile = UserProfile(user=user)
        profile.save()

【讨论】:

  • 感谢您的回答!这样做的推荐方法是什么?我应该在 create_user 视图中执行此操作吗?我在哪里可以阅读此内容(例如,想知道如何为管理员和以前创建的用户创建用户配置文件,但不想浪费您的时间处理一堆后续问题 =)
  • 您可以使用get_or_create 确保用户在访问页面时拥有个人资料,或者您可以创建post_save 信号以在每次创建新用户时创建个人资料。
  • 谢谢!所以我不需要在我的views.py文件中做任何事情?感觉就像我刚刚创建了一个应该在某个地方调用的函数 (save_profile)?
  • 不,您不需要在任何地方调用它。每次创建/更新用户时,它都会自行执行。
【解决方案2】:

在创建User 时,您所做的一切都不会强制创建UserProfile 对象。有两种基本的处理方法:

    1234563 987654328@ 对象已创建(但不是每次都保存,因此请务必检查处理程序中的 created 参数)。
  1. 如果预计用户可能没有配置文件,您需要在尝试访问它时捕获UserProfile.DoesNotExist 异常。如果您经常这样做,请制作某种辅助函数。

已更新以回答信号问题

这里好像也应该添加post_save.connect(create_profile, sender=User)

您需要定义一个名为create_profile 的函数,然后将其连接起来,如图所示。我通常在包含sendermodels.py 文件中正确执行此操作,但在这种情况下,发送者是内置的Django 模型,并且您已经将该模型导入到定义UserProfile 的文件中做的地方。它看起来像:

def create_profile(sender, instance, created, *args, **kwargs):
    # ignore if this is an existing User
    if not created:
        return
    UserProfile.objects.create(user=instance)
post_save.connect(create_profile, sender=User)

【讨论】:

    【解决方案3】:

    回答您更新的问题。模型中已经有一个 save() 方法,每次保存模型时都会调用它(在你调用 create_user() 的情况下)。因此,您需要做的就是定义一个处理函数并将其连接到 post_save 信号。

    def create_extension(sender, instance, created, *args, **kwargs): 如果创建: #做你的事 models.signals.post_save.connect(create_extension, sender=User, dispatch_uid='create_extension')

    我通常将处理函数放在一个单独的文件signals.py中,并在models.py的末尾添加connect()语句

    【讨论】:

      【解决方案4】:

      如果您在尝试上述建议后仍收到此错误,可能是因为您创建的第一个用户(使用 createsuperuser 命令)没有配置文件。

      当我尝试使用该用户登录时出现此错误。我是这样解决的:

      -创建一个新用户。

      -撤消更改。 (删除您为 Profile 编写的代码或添加注释行)

      -登录您的超级用户。

      -给新创建的用户管理员权限。

      现在您可以删除第一个用户。 (没有个人资料的用户)

      【讨论】:

        【解决方案5】:

        只需尝试使用 shell 创建一个新用户以访问管理页面,然后从管理页面为旧用户创建一个配置文件:python manage.py createsuperuser

        要访问 shell,请在您的目录项目中终端输入: python manage.py shell

        【讨论】:

          【解决方案6】:

          如果尚未完成,请先在 admin.py 中注册配置文件模型。

          使用 ./manage.py createsuperuser 创建新的超级用户。

          使用新的超级用户登录。

          从管理面板点击个人资料并添加新条目并从用户下拉列表中选择用户并保存。

          【讨论】:

          • 问题,我无法使用超级用户登录,因为配置文件不存在。
          【解决方案7】:

          对此我有点晚了,但不妥,请分享在 Django 3.0.8 上对我有用的解决方案...

          错误:RelatedObjectDoesNotExist:用户没有个人资料

          这就是我的错误引导我去的地方:

          @login_required
          def dashboard(request):
              if request.method == 'POST':
                  user_form = UserEditForm(instance=request.user, data=request.POST)
                  profile_form = ProfileEditForm(instance=request.user.profile, data=request.POST, files=request.FILES)
          

          注意:您必须登录或保存您的个人资料。

          创建帐户后,您应该能够看到您没有登录,您必须登录才能保存您的个人资料并开始工作。

          【讨论】:

            【解决方案8】:

            进入您的视图,在您的 create_user 函数中执行这些操作

            profile = userprofile()
            profile.user = user
            profile.save()
            

            我也遇到过类似的问题,经过 3 天的研究,我只用上面 3 行代码就能解决这个问题。

            【讨论】:

              【解决方案9】:

              我遇到了同样的问题(= 用户存在,配置文件不存在,但从配置文件端引入了 OneToOne 关系)所以我无法登录管理站点。该应用程序已经在生产中,我无法删除数据库。

              解决方案是创建一个临时视图函数fixme,没有登录要求(但一个难以猜测的 URL)并访问它一次。该视图查询所有用户对象,然后使用get_or_create() 反向查询每个用户的配置文件。如果 Profile 不存在,则已创建。

              打印用于通过日志监控成功。最后从生产应用程序中删除了视图和 URL。

              def fixme(request):
                  users = User.objects.all()
                  for user in users:
                      obj, created = Profile.objects.get_or_create(user=user)
                      print(user.username,' : ',created)
                  print("all done")
                  return HttpResponse("It's done.")
              

              【讨论】:

                【解决方案10】:

                我解决了这个问题(Django 3.8.3-Mongodb)。首先,我创建了signals.py,然后在项目中添加了apps.py。

                signals.py

                from django.db.models.signals import post_save
                from django.dispatch import receiver
                from django.contrib.auth.models import User
                from .models import Profile
                
                @receiver(post_save,sender=User)
                def update_user_profile(sender,instance,created,**kwargs):
                    if created:
                        profile = Profile.objects.create(user =instance)
                

                apps.py

                from django.apps import AppConfig
                
                
                class ProfileConfig(AppConfig):
                    default_auto_field = 'django.db.models.BigAutoField'
                    name = 'Profile'
                
                    def ready(self):
                        import Profile.signals
                

                views.py

                from django.contrib import messages
                from django.contrib.auth.decorators import login_required
                from django.http import HttpResponseRedirect
                from django.urls.base import reverse
                from .forms import ProfileForm
                from .models import Profile
                from django.shortcuts import redirect, render,get_object_or_404
                from django.contrib.auth import update_session_auth_hash
                from django.contrib.auth.forms import PasswordChangeForm
                
                login_required(login_url="user:login")
                def dashboard(request):
                    return render(request,"dashboard.html")
                
                
                @login_required(login_url="user:login")
                def get_profile(request):    
                    
                    profile = get_object_or_404(Profile,user=request.user)
                    
                    return render(request,"profile.html",{"profile":profile})
                
                @login_required(login_url="user:login")
                def update_profile(request):       
                    profile = get_object_or_404(Profile, user=request.user)
                    form = ProfileForm(instance=profile)
                    if request.method=="POST":
                        form = ProfileForm(request.POST,request.FILES,instance=request.user.user_profile)
                        if form.is_valid():
                            form.save()
                            messages.success(request,"Profile is updated successfully")
                            return HttpResponseRedirect(reverse("profile:profile"))   
                        else:
                            return render(request,"profile.html",{"form":form})                 
                            
                    return render(request,"edit.html",{"form":form})
                

                【讨论】:

                  【解决方案11】:

                  问题是您的超级用户未连接到用户配置文件。 有很多方法可以解决这个问题,一种是从 shell 创建用户

                  py manage.py shell
                  
                  > from django.contrib.auth.models import User
                  > 
                  > user=User.objects.create_user('UserName', password='AdminPassword')
                  > user.is_superuser=True   
                  > user.is_staff=True   
                  > user.save()
                  > exit()
                  

                  另一种方式是,您可以在 Models.py 中添加以下代码,以便将您创建的超级用户添加到 UserProfile 的范围内。

                  User.userprofile = property(lambda
                  u:Userprofile.objects.get_or_create(user=u)[0])
                  

                  【讨论】:

                    【解决方案12】:

                    如果您在为您的应用设置身份验证之前创建了一个用户,您需要在终端上创建一个新的超级用户,然后使用该帐户登录。我确定没有按照错误所述创建配置文件!

                    【讨论】:

                    【解决方案13】:

                    有同样的错误。 在应用程序的models.py中添加以下代码解决了这个问题。

                    def create_profile(sender, instance, created, *args, **kwargs):
                        if not created:      # if user already exits then ignore
                            return
                        UserProfile.objects.create(user=instance)
                    post_save.connect(create_profile, sender=User)
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2020-09-03
                      • 2020-07-17
                      • 2021-02-09
                      • 1970-01-01
                      • 1970-01-01
                      • 2020-05-20
                      • 1970-01-01
                      相关资源
                      最近更新 更多