Объект Django 'User' не имеет атрибута 'userprofile'
Я использую Django allauth для аутентификации и создал модель UserProfile для хранения дополнительной информации, которую пользователь может обновить на более поздней стадии. Я пытаюсь использовать сигналы, чтобы экземпляр UserProfile создавался каждый раз, когда пользователь впервые создается, и обновлять UserProfile только если он уже существует.
Проблема заключается в том, что экземпляр UserProfile не создается, выдавая такую ошибку:
Я понимаю, что у объекта User нет атрибута 'userprofile', но я не уверен, как это преодолеть. Я просмотрел похожие решения здесь, здесь и здесь, но, должно быть, я что-то упускаю.
models.py:
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User
from datetime import date, datetime
from django.utils import timezone
from django.db.models.signals import post_save
from django.dispatch import receiver
# Create your models here.
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile', unique=True, on_delete=models.CASCADE)
sex = models.CharField(max_length=1, default='M', blank=True, null=True)
date_of_birth = models.DateField(default=date.today, blank=True, null=True)
date_joined = models.DateField(editable=False, auto_now_add=True, blank=True, null=True)
# durationfield
max_streak = models.PositiveSmallIntegerField(default=0, blank=True, null=True)
curr_streak = models.PositiveSmallIntegerField(default=0, blank=True, null=True)
total_days_clean = models.PositiveSmallIntegerField(default=0, blank=True, null=True)
streak_start_date = models.DateTimeField(editable=True, default=timezone.now, blank=True, null=True)
streak_end_date = models.DateTimeField(editable=True, default=timezone.now, blank=True, null=True)
last_streak_end_date = models.DateTimeField(editable=True, default=timezone.now, blank=True, null=True)
curr_rank = models.CharField(max_length=150, default='n00b', blank=True, null=True)
highest_rank = models.CharField(max_length=150, default='n00b', blank=True, null=True)
bio = models.TextField(default='text', blank=True, null=True)
display_name = models.CharField(max_length=30, default='John Smith', blank=True, null=True)
REQUIRED_FIELDS = ('user',)
email = models.EmailField(blank=True, null=True)
# USERNAME_FIELD = 'username'
# username = models.CharField(max_length = 25, unique=True)
def __str__(self):
return self.user.email
@property
def is_anonymous(self):
"""
Always return False. This is a way of comparing User objects to
anonymous users.
"""
return False
@property
def is_authenticated(self):
"""
Always return True. This is a way of comparing User objects to
anonymous users.
"""
return True
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.userprofile.save()
forms.py:
from allauth.account.forms import SignupForm
from django import forms
from .models import User, UserProfile
from django.forms.widgets import NumberInput
import datetime
class UpdateUserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
# fields to be added in this form
fields = ['display_name', 'date_of_birth', 'bio']
views.py:
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
from django.http import HttpResponse
from .models import User, UserProfile
from .forms import UpdateUserProfileForm
def update_user_profile(request):
# form = UpdateUserProfileForm(request.POST or None)
form = UpdateUserProfileForm(request.POST, instance=request.user.userprofile)
if form.is_valid():
form.save()
return redirect('profile')
messages.success(request, ('Your profile was successfully updated!'))
else:
messages.error(request, ('Please correct the error below.'))
context = {
'form': form
}
return render(request, 'update_profile.html', context)
Любая помощь будет принята с благодарностью, спасибо.
Это происходит, потому что вы устанавливаете related_name='profile', а затем вызываете его с помощью instance.userprofile.save(). Измените это на:
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
и все должно работать гладко :)