Home > Net >  Django 'User' object has no attribute 'userprofile' but instance is still create
Django 'User' object has no attribute 'userprofile' but instance is still create

Time:02-27

I'm using Django allauth for authentication and have created a UserProfile model to store additional details which a user can updated at a later stage. I'm trying to use signals to have the UserProfile instance created whenever a User is first created and to only update the UserProfile if it already exists.

The problem I face is the UserProfile instance is created but gives out this error shown in the call stack. When I remove the signal code, run the server and log in as admin I can see it has been created but having the signal code uncommented out prevents me from even logging in as admin or from trying to login/signup as a new user in the application.

Traceback:

Traceback (most recent call last):
  File "/Users/QP/env/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/Users/QP/env/lib/python3.8/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/QP/env/lib/python3.8/site-packages/django/contrib/admin/options.py", line 622, in wrapper
    return self.admin_site.admin_view(view)(*args, **kwargs)
  File "/Users/QP/env/lib/python3.8/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/Users/QP/env/lib/python3.8/site-packages/django/views/decorators/cache.py", line 57, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "/Users/QP/env/lib/python3.8/site-packages/django/contrib/admin/sites.py", line 236, in inner
    return view(request, *args, **kwargs)
  File "/Users/QP/env/lib/python3.8/site-packages/django/utils/decorators.py", line 43, in _wrapper
    return bound_method(*args, **kwargs)
  File "/Users/QP/env/lib/python3.8/site-packages/django/views/decorators/debug.py", line 90, in sensitive_post_parameters_wrapper
    return view(request, *args, **kwargs)
  File "/Users/QP/env/lib/python3.8/site-packages/django/utils/decorators.py", line 43, in _wrapper
    return bound_method(*args, **kwargs)
  File "/Users/QP/env/lib/python3.8/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/Users/QP/env/lib/python3.8/site-packages/django/contrib/auth/admin.py", line 99, in add_view
    return self._add_view(request, form_url, extra_context)
  File "/Users/QP/env/lib/python3.8/site-packages/django/contrib/auth/admin.py", line 126, in _add_view
    return super().add_view(request, form_url, extra_context)
  File "/Users/QP/env/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1670, in add_view
    return self.changeform_view(request, None, form_url, extra_context)
  File "/Users/QP/env/lib/python3.8/site-packages/django/utils/decorators.py", line 43, in _wrapper
    return bound_method(*args, **kwargs)
  File "/Users/QP/env/lib/python3.8/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/Users/QP/env/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1549, in changeform_view
    return self._changeform_view(request, object_id, form_url, extra_context)
  File "/Users/QP/env/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1599, in _changeform_view
    self.save_model(request, new_object, form, not add)
  File "/Users/QP/env/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1108, in save_model
    obj.save()
  File "/Users/QP/env/lib/python3.8/site-packages/django/contrib/auth/base_user.py", line 66, in save
    super().save(*args, **kwargs)
  File "/Users/QP/env/lib/python3.8/site-packages/django/db/models/base.py", line 743, in save
    self.save_base(using=using, force_insert=force_insert,
  File "/Users/QP/env/lib/python3.8/site-packages/django/db/models/base.py", line 791, in save_base
    post_save.send(
  File "/Users/QP/env/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 170, in send
    return [
  File "/Users/QP/env/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 171, in <listcomp>
    (receiver, receiver(signal=self, sender=sender, **named))
  File "/Users/QP/core/models.py", line 64, in save_user_profile
    instance.userprofile().save()

Exception Type: AttributeError at /admin/auth/user/add/
Exception Value: 'User' object has no attribute 'userprofile'

I understand that the User object has no 'userprofile' attribute but i'm not sure how to overcome this. I have looked to similar solutions here, here and here but I must be missing something.

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)   

How do I get round this? Any help is appreciated, thanks.

CodePudding user response:

It happens, because you set related_name='profile' and then you call it with instance.userprofile.save(). Change it to:

@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()

and it should work smoothly :)

  • Related