RelatedObjectDoesNotExist:用户没有用户配置文件

RelatedObjectDoesNotExist: User has no userprofile

所以我用这样的字段 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 上面写着:

Like pre_save, but sent at the end of the save() method.

好吧,所以我查找 pre_save,它说:

This is sent at the beginning of a model’s save() method.

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

所以现在我准备开始看例子了,所以我 google:

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)

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

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

在您的 views.py 中,您可以使用 get_or_create 以便在用户没有 userprofile 时为该用户创建 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()

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

  1. 如果你总是想要一个 UserProfile 存在(这似乎是你给 score 一个 default 值的情况,创建一个 post_save 处理程序在创建 User 对象时创建一个新的配置文件(但不是每次保存它时,因此请确保检查处理程序中的 created 参数)。

  2. 如果预期用户可能没有个人资料,则您需要在尝试访问它时捕获 UserProfile.DoesNotExist 异常。如果你经常这样做,做一些辅助功能。

已更新以回答信号问题

It also looks like somewhere around here post_save.connect(create_profile, sender=User) should be added?

您需要定义一个名为 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)

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

def create_extension(sender, instance, created, *args, **kwargs):
    if created:
        # do your thing

models.signals.post_save.connect(create_extension, sender=User, dispatch_uid='create_extension')

我通常将处理函数放在一个单独的文件中 signals.py 并在 models.py

末尾添加 connect() 语句

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

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

-创建一个新用户。

-撤消更改。 (擦除您为配置文件编写的代码或将它们设为注释行)

-登录您的超级用户。

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

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

只需尝试使用 shell 创建新用户以访问管理页面,然后从管理页面为旧用户创建个人资料:python manage.py 创建超级用户

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

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

使用 ./manage.py createsuperuser.

创建新的超级用户

使用新的超级用户登录。

在管理面板中单击配置文件并添加新条目并从用户下拉列表中选择用户并保存。

我有点晚了,但我很抱歉,请分享在 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)

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

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

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

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

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

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

解决方案是创建一个没有登录要求的临时视图函数 fixme(但很难猜测 URL)并访问它一次。该视图查询了所有 User 对象,然后用 get_or_create() 反向查询了每个 User 的 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.")

我解决了这个问题(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})

问题是您的超级用户未连接到用户配置文件。 有多种方法可以解决此问题,一种是从 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])

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

同样的错误。 在 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)

我遇到了同样的错误,但我通过创建下面的信号示例解决了这个问题

然后我编辑了我的 apps.py 如下:

`从 django.apps 导入 AppConfig

class 博客配置(AppConfig): default_auto_field = 'django.db.models.BigAutoField' 姓名 = 'app_name'

def ready(self):
    import app_name.signals`