0

I'd like each User to be able to create an Account (max of one account each). The user in session won't be able to see the option to create an account unless they are logged in/authenticated. When I log in and click submit on the Create Account form, this error is raised:

'ValueError at /accounts/create/ Cannot assign "<SimpleLazyObject: <User: Jimmy>>": "Account.user" must be a "User" instance.'

My models.py:

from django.db import models
from django.contrib import auth
from django.utils.text import slugify
from django.urls import reverse

from django import template
register = template.Library()

class User(auth.models.User,auth.models.PermissionsMixin):

def __str__(self):
    return self.username

class Account(models.Model):
user = models.OneToOneField(User,related_name='customer_account',on_delete=models.CASCADE)
first_name = models.CharField(max_length=30,blank=True)
surname = models.CharField(max_length=30,blank=True)
billing_address = models.TextField(blank=True)
delivery_address = models.TextField(blank=True)

def __str__(self):
    return f"Account: {self.user.username}"

def get_absolute_url(self):
    return reverse('about',kwargs={'username':self.user.username,
                                                            'pk':self.pk})

Views.py:

from django.shortcuts import render
from django.urls import reverse_lazy
from django.contrib.auth.mixins import LoginRequiredMixin
from braces.views import SelectRelatedMixin
from django.views.generic import (CreateView, UpdateView,
                                ListView, DetailView,
                                TemplateView,)
from . import forms
from . import models
from django.core.exceptions import ObjectDoesNotExist
from django.shortcuts import redirect
from django.contrib.auth import get_user_model
# User = get_user_model()


class SignUp(CreateView):
    form_class = forms.CreateCustomerForm
    success_url = reverse_lazy('login')
    template_name = 'accounts/signup.html'


class CreateAccount(LoginRequiredMixin,CreateView):
    model = models.Account
    fields = ['first_name','surname','billing_address','delivery_address']
    template_name = 'accounts/create_account.html'

    def form_valid(self,form):
            self.object = form.save(commit=False)
            self.object.user = self.request.user
            self.object.save()
            return super().form_valid(form)

Forms.py:

from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import get_user_model
from . import models

class CreateCustomerForm(UserCreationForm):
class Meta:
    model = get_user_model()
    fields = ('username','email','password1','password2')

def __init__(self,*args,**kwargs):
    super().__init__(*args,**kwargs)
    self.fields['username'].label = 'Username'
    self.fields['email'].label = "Email Address"

Urls.py:

 from django.conf.urls import url
from accounts import views
from django.contrib.auth import views as auth_views

app_name = 'accounts'

urlpatterns = [
    url(r'^login/$',auth_views.LoginView.as_view(template_name='accounts/login.html'),name='login'),
    url(r'^logout/$',auth_views.LogoutView.as_view(),name='logout'),
    url(r'^signup/$',views.SignUp.as_view(),name='signup'),
    url(r'^create/$',views.CreateAccount.as_view(),name='create'),

]

Here is where things seem to go wrong according to the Traceback section:

    line 39, in form_valid
            self.object.user = User …
▼ Local vars
Variable    Value
User    
<SimpleLazyObject: <User: Jimmy>>
__class__   
<class 'accounts.views.CreateAccount'>
form    
<AccountForm bound=True, valid=True, fields=(first_name;surname;billing_address;delivery_address)>
self    
<accounts.views.CreateAccount object at 0x000001C9E70DBC40>


 line 310, in __set__
        super().__set__(instance, value) …
▼ Local vars
Variable    Value
__class__   
<class 'django.db.models.fields.related_descriptors.ForwardOneToOneDescriptor'>
instance    
Error in formatting: RelatedObjectDoesNotExist: Account has no user.
self    
<django.db.models.fields.related_descriptors.ForwardOneToOneDescriptor object at 0x000001C9E6C72250>
value   
<SimpleLazyObject: <User: Jimmy>>

Thanks in advance if you're able to help.

jem4789
  • 89
  • 9
  • Does this answer your question? [django: Purpose of django.utils.functional.SimpleLazyObject?](https://stackoverflow.com/questions/10506766/django-purpose-of-django-utils-functional-simplelazyobject) – etnguyen03 Dec 07 '20 at 22:15
  • @etnguyen03 To an extent - I changed the user variable in the Account model to this: – jem4789 Dec 09 '20 at 11:01
  • 'class Account(models.Model): user = models.OneToOneField(get_user_model(),related_name='customer_account',on_delete=models.CASCADE)' – jem4789 Dec 09 '20 at 11:02
  • However, I'm getting this error now: IntegrityError at /accounts/create/ FOREIGN KEY constraint failed – jem4789 Dec 09 '20 at 11:04
  • Happening at self.object.save in form_valid(), in the CreateView. This is the second to last traceback!: – jem4789 Dec 09 '20 at 11:05
  • This was a really helpful article in case anybody's looking to solve the problem I had: https://learndjango.com/tutorials/django-best-practices-referencing-user-model – jem4789 Dec 09 '20 at 14:12

1 Answers1

0

This article was really helpful and cleared up the issue I was having:

https://learndjango.com/tutorials/django-best-practices-referencing-user-model

I deleted the User model in my models.py file, then altered the 'user' field in my Account model to this:

> user = models.OneToOneField(settings.AUTH_USER_MODEL,related_name='customer_account',on_delete=models.CASCADE)

Then kept this in views.py (as before) to get the user model for the views:

from django.contrib.auth import get_user_model
User = get_user_model()
jem4789
  • 89
  • 9