Django 'User' object has no attribute 'phone' - python

I want to add a custom field called phone but I get this error:
'User' object has no attribute 'phone'
What I did in models.py is:
class Customer(models.Model):
user = models.OneToOneField(User, null=True, blank=True, on_delete=models.CASCADE)
...
phone = models.CharField(max_length=17, null=True, unique=True)
...
def __str__(self):
return str(self.user)
and I have forms.py
class CreatUserForm(UserCreationForm):
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed.")
first_name = forms.CharField()
last_name = forms.CharField()
email = forms.EmailField()
phone = forms.CharField(validators=[phone_regex], max_length=17)
class Meta:
model = User
fields = ['first_name', 'last_name', 'username', 'email', 'phone', 'password1', 'password2']
and finally in views.py I have the following function:
#unauthenticated_user
def registerPage(request):
form = CreatUserForm()
if request.method == 'POST':
form = CreatUserForm(request.POST)
if form.is_valid():
user = form.save()
username = form.cleaned_data.get('username')
group = Group.objects.get(name='customers')
user.groups.add(group)
first_name = user.first_name
last_name = user.last_name
email = user.email
phone = user.phone
Customer.objects.create(
user=user, first_name=first_name, last_name=last_name, email=email, phone=phone,
)
messages.success(request, username + ' created!')
return redirect('login')
context = {'form': form}
return render(request, 'main/page-register.html', context)
But I can't get phone from my users!

It is likely better to work with two forms here, one for the User, and one for the Customer, and then "link" the two at the view level:
class CustomerForm(ModelForm):
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message='Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed.')
phone = forms.CharField(validators=[phone_regex], max_length=17)
class Meta:
model = Customer
fields = ['phone']
then we can combine both forms with:
#unauthenticated_user
def registerPage(request):
if request.method == 'POST':
form = UserCreationForm(request.POST, request.FILES)
form2 = CustomerForm(request.POST, request.FILES)
if form.is_valid() and form2.is_valid():
user = form.save()
form2.instance.user = user
form2.save()
group = Group.objects.get(name='customers')
user.groups.add(group)
messages.success(request, username + ' created!')
return redirect('login')
else:
form = UserCreationForm()
form2 = CustomerForm()
context = {'form': form, 'form2': forom2}
return render(request, 'main/page-register.html', context)
in the template, then both forms are rendered:
<form action="…" method="post">
{% csrf_token %}
{{ form1 }}
{{ form2 }}
Create customer
</form>
Your customer should not have the same fields as the user: you are then duplicating data, and it is hard to keep data in sync.

Related

Creating a simple multiple users app in Django

So I've created 3 different users: admins, developers, and project managers. When I use the individual signup forms for each of these users and log out, it works, but then I when try to use the login form, it seems to me that it's acting like the signup form. Because when I input the same user details as the one I just created into the login form, it throws up the built-in error message, 'A user with that user name already exists' I'm not sure how to proceed from here.
Here's what I have so far.
models.py
class CustomUser(AbstractUser):
ACCOUNT_TYPE_CHOICES = (
('admin', 'Admin'),
('developer', 'Developer'),
('project_manager', 'Project Manager')
)
account_type = models.CharField(max_length=20, choices=ACCOUNT_TYPE_CHOICES)
login and signupviews
class LoginView(View):
def get(self, request):
# Render the login form
form = LoginForm()
return render(request, 'users/login.html', {'form': form})
def post(self, request):
# Get the form data from the request
form = LoginForm(request.POST)
# Validate the form data
if form.is_valid():
# Get the username and password from the form
username = form.cleaned_data['username']
password = form.cleaned_data['password']
# Authenticate the user
user = authenticate(request, username=username, password=password)
# If the user is authenticated, log them in and redirect to the homepage
if user is not None:
login(request, user)
if user.account_type == 'admin':
return redirect('admin_home')
elif user.account_type == 'developer':
return redirect('developer_home')
elif user.account_type == 'project_manager':
return redirect('projectmanager_home')
return redirect('home')
# If the user is not authenticated, render the login form again with an error message
else:
form.add_error(None, 'Invalid username or password')
return render(request, 'users/login.html', {'form': form})
else:
return render(request, 'users/login.html', {'form': form})
class LogoutView(View):
def get(self, request):
# Log out the user and redirect to the login page
logout(request)
return redirect('home')
class AdminSignUpView(CreateView):
form_class = AdminSignUpForm
template_name = 'users/admin_signup.html'
success_url = '/admin_home/'
def form_valid(self, form):
# Create the user and log them in
user = form.save()
login(self.request, user)
return redirect(self.success_url)
class DeveloperSignUpView(CreateView):
form_class = DeveloperSignUpForm
template_name = 'users/developer_signup.html'
success_url = '/developer_home/'
def form_valid(self, form):
# Create the user and log them in
user = form.save()
login(self.request, user)
return redirect(self.success_url)
class ProjectManagerSignUpView(CreateView):
form_class = ProjectManagerSignUpForm
template_name = 'users/projectmanager_signup.html'
success_url = '/projectmanager_home/'
def form_valid(self, form):
# Create the user and log them in
user = form.save()
login(self.request, user)
return redirect(self.success_url)
forms.py
class AdminSignUpForm(forms.ModelForm):
# Define the form fields for the admin sign-up form
account_type = forms.CharField(max_length=20, widget=forms.HiddenInput(), initial='admin')
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
email = forms.EmailField()
username = forms.CharField(max_length=150)
password = forms.CharField(max_length=128, widget=forms.PasswordInput())
class Meta:
model = CustomUser
fields = ['first_name', 'last_name', 'email', 'username', 'password']
class DeveloperSignUpForm(forms.ModelForm):
# Define the form fields for the developer sign-up form
account_type = forms.CharField(max_length=20, widget=forms.HiddenInput(), initial='developer')
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
email = forms.EmailField()
username = forms.CharField(max_length=150)
password = forms.CharField(max_length=128, widget=forms.PasswordInput())
class Meta:
model = CustomUser
fields = ['first_name', 'last_name', 'email', 'username', 'password']
class ProjectManagerSignUpForm(forms.ModelForm):
# Define the form fields for the admin sign-up form
account_type = forms.CharField(max_length=20, widget=forms.HiddenInput(), initial='project_manager')
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
email = forms.EmailField()
username = forms.CharField(max_length=150)
password = forms.CharField(max_length=128, widget=forms.PasswordInput())
class Meta:
model = CustomUser
fields = ['first_name', 'last_name', 'email', 'username', 'password']
class LoginForm(forms.ModelForm):
class Meta:
model = CustomUser
fields = ['username', 'password']
widgets = {
'password': forms.PasswordInput(),
}
login template
{% block content %}
<h1>Login</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Log in</button>
</form>
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
{% endblock %}
Let me know if you need any more information.

Trying to extend User to UserProfile in form Django

Hi I am having serious trouble this getting this form to work. When I try to run my program it gets to print("4") then throws the error
UNIQUE constraint failed: slug_trade_app_userprofile.user_id
To be clear the new user i am creating doesnt exist prior to clicking submit on the form
It seems like profile is trying to create a new user again but since (i think) user created a new user, that user already exists its throwing the error. HELP!!
Views.py
def signup(request):
if request.method == 'POST':
user_form = UserForm(data=request.POST)
profile_form = UserProfileForm(data=request.POST)
if user_form.is_valid() and profile_form.is_valid():
print("1")
user = user_form.save(commit=False)
user.save()
print("2")
profile = profile_form.save(commit=False)
print("3")
profile.user = user
print("4")
profile.save()
print("5")
user = authenticate(username=user_form.cleaned_data['email'],
password=user_form.cleaned_data['password1'],
)
login(request, user)
return redirect('/home')
else:
user_form = UserForm()
profile_form = UserProfileForm()
return render(request, 'slug_trade_app/signup.html', {'user_form': user_form, 'profile_form': profile_form})
models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
profile_picture = models.ImageField(upload_to='static/profile_pictures', blank=True )
bio = models.TextField(max_length=500, blank=True)
on_off_campus = models.CharField(max_length=3,
default="on",
choices=CAMPUS_STATUS)
forms.py
class UserForm(UserCreationForm):
email = forms.EmailField(required=False)
class Meta:
model = User
fields = (
'first_name',
'last_name',
'email',
'password1',
'password2',
)
def save(self, commit=True):
user = super(UserForm, self).save(commit=False)
user.username = self.cleaned_data['email']
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
class UserProfileForm(forms.ModelForm):
class Meta():
model = UserProfile
fields = ('profile_picture', 'bio', 'on_off_campus')
Try profile_form = UserProfileForm(instance=request.user) Also I believe profile.user = user should be profile.user = request.user otherwise user refers to the user form not the user instance

Django auth.models User One-To-Many (1048, "Column 'user_id' cannot be null")

I'm new to django and my task is to make user able to create a lot profiles after registration when he's logged in.
This is my models.py:
class Profile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(blank=False, max_length=100)
lastname = models.CharField( blank=False, max_length=100)
city = models.CharField( blank=True, max_length=100)
country = models.CharField( blank=True, max_length=100)
phonenumber = models.CharField(blank=False, null=True, max_length=20)
email = models.EmailField(blank=False, max_length=100)
date_of_birth = models.DateField( blank=True, null=True)
date_of_addition = models.DateField(auto_now=True, editable=False, null=True)
When I create my user, do login and press create profile button I get :
django.db.utils.IntegrityError: (1048, "Column 'user_id' cannot be null")
This is my views.py:
#login_required
def profile_create(request):
data = dict()
if request.method == 'POST':
form = ProfileForm(request.POST)
if form.is_valid():
form.save()
data['form_is_valid'] = True
profiles = Profile.objects.all()
data['html_profile_list'] = render_to_string('basic_app/users_list_1_10.html', {'profiles': profiles})
else:
data['form_is_valid'] = False
else:
form = ProfileForm()
context = {'form': form}
data['html_form'] = render_to_string('basic_app/partial_profile_create.html', context, request=request)
return JsonResponse(data)
def register(request):
registered = False
if request.method == "POST":
user_form = UserForm(data=request.POST)
if user_form.is_valid():
user = user_form.save()
user.set_password(user.password)
user.save()
registered = True
else:
print(user_form.errors)
else:
user_form = UserForm()
return render(request,'basic_app/registration.html',{'user_form':user_form,'registered':registered})
This is my forms.py:
from django import forms
from django.forms import ModelForm
from django.contrib.auth.models import User
from .models import Profile
class ProfileForm(ModelForm):
class Meta:
model = Profile
fields = ('name', 'lastname', 'city', 'country', 'phonenumber', 'email', 'date_of_birth')
class UserForm(ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
username = forms.CharField(help_text=False)
class Meta():
model = User
fields = ('username','password')
Thanks
It happens because in your Profile model you have user field which is ForeignKey. In Django ForeignKey is required by default, which means that you can't create new Profile without specifying user field. But you don't provide user in ProfileForm.
You can either provide user in ProfileForm or set user field as not required by adding:
user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)
I should request user before saving ProfileForm:
#login_required
def profile_create(request):
data = dict()
if request.method == 'POST':
form = ProfileForm(request.POST)
if form.is_valid():
add = form.save(commit=False)
add.user = request.user
add.save()
data['form_is_valid'] = True
profiles = Profile.objects.all()
data['html_profile_list'] = render_to_string('basic_app/users_list_1_10.html', {'profiles': profiles})
else:
data['form_is_valid'] = False
else:
form = ProfileForm()
context = {'form': form}
data['html_form'] = render_to_string('basic_app/partial_profile_create.html', context, request=request)
return JsonResponse(data)

Django 1.10 IntegrityError on register

I'm trying to set up a registration page and I have a model CafeUser which serves as the profile for the User model. I used a tutorial to set up a signal receiver so I could create a CafeUser for all new registered users.
models.py:
class CafeUser(models.Model):
user = models.ForeignKey(User, unique=True, related_name="cafeuser")
phone_number = models.CharField(max_length=15)
birth_date = models.DateField('birthdate')
def __str__(self):
return self.user.first_name + " " + self.user.last_name
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
CafeUser.objects.create(user=instance)
views.py:
def register(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save()
user.refresh_from_db()
user.cafeuser.birth_date = form.cleaned_data.get('birth_date')
user.cafeuser.phone_number = form.cleaned_data.get('phone_number')
user.save()
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=user.username, password=raw_password)
login(request, user)
return redirect('cafe:index')
else:
form = SignUpForm()
return render(request, 'cafe/register.html', {'form': form})
forms.py
class SignUpForm(UserCreationForm):
first_name = forms.CharField(max_length=30, required=False, help_text='Optional.')
last_name = forms.CharField(max_length=30, required=False, help_text='Optional.')
email = forms.EmailField(max_length=254, help_text='Required. Inform a valid email address.')
birth_date = forms.DateField(help_text='Rquired.')
phone_number = forms.CharField(max_length=15)
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email', 'password1', 'password2',)
When I try testing the registration, the user is created, however, the CafeUser is not:
IntegrityError at /register/ null value in column "birth_date"
violates not-null constraint DETAIL: Failing row contains (7, 8,
null, ).
register.html:
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="submit">Register</button>
</form>
Please let me know how to fix this and any other tips you might have for improving this unit of code.
The problem was that the CafeUser was not saving. Based on what I read in the docs somewhere, I had thought that calling user.save() was supposed to automatically call save() on the profile module as well - and I'm still not sure why it doesn't. So I just wrote the call user.cafeuser.save() myself anyway:
if form.is_valid():
user = form.save()
user.refresh_from_db()
user.cafeuser.birth_date = form.cleaned_data.get('birth_date')
user.cafeuser.phone_number = form.cleaned_data.get('phone_number')
user.cafeuser.save() # Apparently this had to be added
user.save()
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=user.username, password=raw_password)
login(request, user)
return redirect('cafe:index')

Django - duplicate key value violates unique constraint

In my Django project i create an app to have additional information about registered users. So my model looks like this:
class UserProfile(models.Model):
class Meta:
verbose_name_plural = u'User Profile'
user = models.OneToOneField(User)
birthday = models.DateField(blank=True, null=True)
avatar = models.ImageField(upload_to='media/profile/avatar', blank=True, null=True)
name = models.CharField(blank=True, null=True, max_length=20)
surname = models.CharField(blank=True, null=True, max_length=50)
phone = models.CharField(blank=True, null=True, max_length=12)
def __unicode__(self):
return '%s' % self.user
Here is my registration form:
class RegistrationForm(ModelForm):
username = forms.CharField(label=(u'Username'))
email = forms.EmailField(label=(u'Email'))
password = forms.CharField(label=(u'Password'), widget=forms.PasswordInput(render_value=False))
password1 = forms.CharField(label=(u'Password'), widget=forms.PasswordInput(render_value=False))
class Meta:
model = UserProfile
exclude = ('user',)
fields = ('username', 'email', 'password', 'password1')
def clean_email(self):
email = self.cleaned_data['email']
try:
User.objects.get(email=email)
except User.DoesNotExist:
return email
raise forms.ValidationError("User with same email already exist, please change your email")
And here is view of my registration form:
def UserProfileRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect('/profile/')
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = User.objects.create_user(username=form.cleaned_data['username'], email=form.cleaned_data['email'], password=form.cleaned_data['password'])
user.save()
user_profile = UserProfile(user=user)
user_profile.save()
return HttpResponseRedirect('/profile/')
else:
return render(request, 'profiles/registration.html', {'form':form})
else:
form = RegistrationForm()
context = {'form':form}
return render (request, 'profiles/registration.html', context)
In user profile i create modelform where user can fill the fields from UserProfile model:
class ExtraProfileDataForm(ModelForm):
name = forms.CharField(label=(u'Enter your name'))
surname = forms.CharField(label=(u'Enter your surname'))
phone = forms.CharField(label=(u'Enter your phone'))
birthday = forms.DateField(label=(u'Enter birthday'))
avatar = forms.ImageField(label=(u'Enter avatar'))
class Meta:
model = UserProfile
fields = ('name', 'surname', 'phone', 'birthday', 'avatar')
def __init__(self, *args, **kwargs):
super(ExtraProfileDataForm, self).__init__(*args, **kwargs)
for key in self.fields:
self.fields[key].required = False
This is the view of the model form:
#login_required
def UserFullDataForm(request):
if request.method == 'POST':
form = ExtraProfileDataForm(request.POST)
if form.is_valid():
profile_user = request.user
user_profile = UserProfile(user=profile_user)
user_profile.name = form.cleaned_data['name']
user_profile.surname = form.cleaned_data['surname']
user_profile.phone = form.cleaned_data['phone']
user_profile.birthday = form.cleaned_data['birthday']
user_profile.avatar = form.cleaned_data['avatar']
user_profile.save()
return HttpResponseRedirect('/profile/')
else:
return render(request, 'profiles/extra_profile.html', {'form':form})
else:
form = ExtraProfileDataForm()
context = {'form':form}
return render (request, 'profiles/extra_profile.html', context)
But when I fill this form I got the error:
duplicate key value violates unique constraint "profiles_userprofile_user_id_key" DETAIL: Key (user_id)=(23) already exists.
On the traceback i see that error in this line user_profile.save(). As i understand it happens because this script create new item with same id but not update it. What i have to change on my code to update existing item but not to create. Thank you.
You need to use get_or_create, which will return an existing item if it was found; otherwise create a new instance of the model.
In your user profile update view:
user_profile, created = UserProfile.objects.get_or_create(user=profile.user)
Now, instead of creating a new profile each time - you are updating if a profile for that user already exists.

Categories

Resources