I am new to Django.I am creating a user registration by using the built in Django User model and Usercreation form. I am trying to extend the built-in User Model in Django so I can include an extra field company name.I am encountering this recurring error below.I would really appreciate any help in trying to solve this problem.
RelatedObjectDoesNotExist User has no Profile
(1)Here is my Model.py of the Profile model
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
Company_name = models.CharField(max_length=30)
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
(2.)Here is my views.py.I am trying to update the profile model each time a new user instance is created.It seems like I have to link the create_user_profile and save_user_profile functions to my view but I am not too sure how to do this.
def Register(request):
if request.method == 'POST':
User_form = RegisterRecruiterForm(request.POST, instance=request.user)
Profile_form = ProfileForm(request.POST, instance=request.user.profile)
if User_form.is_valid() and Profile_form. is_valid():
User_form.save()
Profile_form.save()
return HttpResponse('you are now registered')
else:
User_form = RegisterRecruiterForm(instance=request.user)
Profile_form = ProfileForm(instance=request.user.profile)
return render(request, 'Register.html', {
'User_form': User_form,
'Profile_form': Profile_form
})
3.Here is my forms.py.
class RegisterRecruiterForm(UserCreationForm):
email = forms.EmailField(max_length=254, help_text='Required. Inform a valid email address.')
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2')
def save(self, commit=True):
user = super(RegisterRecruiterForm, self).save(commit=False)
user.email(self.cleaned_data["email"])
user.username(self.cleaned_data["username "])
user.password(self.cleaned_data["password1 "])
user.password(self.cleaned_data["password2 "])
if user.password1 != user.password2:
raise forms.validationError("Password do not match")
return Profile.Company_name
if commit:
user.save()
return user
class ProfileForm(forms.ModelForm):
Company_name = forms.CharField(max_length=10,help_text='Required')
class Meta:
model = Profile
fields = ('Company_name',)
def save(self, commit=True):
Profile = super(ProfileForm, self).save(commit=False)
Profile.Company_name(self.cleaned_data["Company_name"])
if commit:
Profile.save()
return Profile
As I can see, your problem is that you are trying to get "request.user.profile" in this line:
Profile_form = ProfileForm(request.POST, instance=request.user.profile)
In your models the "User" doesn't has a "Profile" but a "Profile" has a "User", so the correct way to get this profile is:
profile = Profile.objects.get(user = request.user)
Profile_form = ProfileForm(request.POST, instance = profile)
This fix your problem with the "RelatedObjectDoesNotExist" error. If you have another error, you can open a new question.
Finally, you "Register" function will be:
def Register(request):
if request.method == 'POST':
User_form = RegisterRecruiterForm(request.POST, instance=request.user)
profile = Profile.objects.get(user = request.user)
Profile_form = ProfileForm(request.POST, instance = profile)
if User_form.is_valid() and Profile_form. is_valid():
User_form.save()
Profile_form.save()
return HttpResponse('you are now registered')
else:
User_form = RegisterRecruiterForm(instance=request.user)
profile = Profile.objects.get(user = request.user)
Profile_form = ProfileForm(request.POST, instance = profile)
return render(request, 'Register.html', {
'User_form': User_form,
'Profile_form': Profile_form
})
Related
I am working on a registration page. I extended django's User model to add additional fields. I have two forms connected with OnetoOnefield. I am getting this error.
DoesNotExist at /register/
Influencer matching query does not exist.
I think what I am doing wrong is creating User and Influencer model at the same time.
My models.py file:
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Influencer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(blank=True, null=True)
ig_url = models.CharField(max_length=100, blank=True, null=True)
def __str__(self):
return f"{self.user.first_name} {self.user.last_name}"
#receiver(post_save, sender=User)
def create_influencer(sender, instance, created, **kwargs):
if created:
Influencer.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_influencer(sender, instance, **kwargs):
instance.influencer.save()
My forms.py file:
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
class InfluencerProfileForm(forms.ModelForm):
class Meta:
model = Influencer
fields = ('bio', 'ig_url')
My views.py file:
def register(request):
user_form = UserForm()
profile_form = InfluencerProfileForm()
if request.method == 'POST':
user_form = UserForm(request.POST, instance=request.user)
profile = Influencer.objects.get(user=request.user)
profile_form = InfluencerProfileForm(request.POST, instance=profile)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
messages.success(request, 'Your profile was successfully updated!')
return redirect('settings:profile')
else:
messages.error(request, 'Please correct the error below.')
return render(request, 'accounts/register.html', {
'user_form': user_form,
'profile_form': profile_form
})
I think the problem is in two places. One, you have a signal which creates Influencer instance where you al. Second, you are assuming you will have a Influencer instance before creating one. You can remove the signals and try with the following code:
def register(request):
user_form = UserForm(request.POST or None)
profile_form = InfluencerProfileForm(request.POST or None)
if request.method == 'POST':
if request.user.is_authenticated:
user_form = UserForm(request.POST, instance=request.user)
try:
profile_form = InfluencerProfileForm(request.POST, instance=request.user.influencer) # due to OneToOne relation, it will work
except:
pass
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
profile = profile_form.save(commit=False)
profile.user = user
profile.save()
messages.success(request, 'Your profile was successfully updated!')
return redirect('settings:profile')
else:
messages.error(request, 'Please correct the error below.')
return render(request, 'accounts/register.html', {
'user_form': user_form,
'profile_form': profile_form
})
I have a site where I need to update my UserProfileInfo model, which is how I am extending the User model.
However, whenever I save the User model, the UserProfileInfo does not, meaning in the admin, the User model has the first_name and last_name variables filled out, however the UserProfileInfo does not.
Here is some code.
MODELS.PY
class UserProfileInfo(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,max_length=30)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
description = models.TextField(max_length=150)
website = models.URLField(max_length=200,blank=True,null=True)
image = ProcessedImageField(upload_to='profile_pics',
processors=[ResizeToFill(150, 150)],
default='default.jpg',
format='JPEG',
options={'quality': 60})
joined_date = models.DateTimeField(blank=True,null=True,default=timezone.now)
verified = models.BooleanField(default=False)
moderator = models.BooleanField(default=False)
tags = TaggableManager()
def __str__(self):
return f'{self.user.username} Profile'
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
#receiver(post_save, sender=User)
def create_or_update_user_profile(sender, instance, created, **kwargs):
if created:
UserProfileInfo.objects.create(user=instance)
else:
instance.userprofileinfo.save()
In the receiver, I want to update both, but it is not.
FORMS.PY
class UserProfileInfoForms(UserCreationForm):
email = forms.EmailField()
class Meta():
model = User
fields = ['username','first_name','last_name','email']
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username','email']
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = UserProfileInfo
fields = ['image','description','tags','website']
And finally here is the view
VIEWS.PY
#login_required
def profile_update(request):
if request.method == 'POST':
u_form = UserUpdateForm(request.POST, instance=request.user)
p_form = ProfileUpdateForm(request.POST,
request.FILES,
instance=request.user.userprofileinfo)
if u_form.is_valid() and p_form.is_valid():
u_form.save()
p_form.save()
messages.success(request, f'Your account has been updated!')
return redirect('mainapp:profile')
else:
u_form = UserUpdateForm(instance=request.user)
p_form = ProfileUpdateForm(instance=request.user.userprofileinfo)
context = {
'u_form': u_form,
'p_form': p_form
}
return render(request,'mainapp/profile_update.html',context)
So here, I'm saving both the UserUpdateForm and ProfileUpdateForm
And finally here are my signals
SIGNALS.PY
#receiver(post_save, sender=User)
def create_or_update_user_profile(sender, instance, created, **kwargs):
if created:
UserProfileInfo.objects.create(user=instance)
else:
instance.userprofileinfo.save()
#receiver(post_save,sender=User)
def save_profile(sender,instance,**kwargs):
instance.userprofileinfo.save()
I have also included my signals.py in the apps.py file, so it is working.
So how can I make it so that the UserProfileInfo model is updated when the User model is updated? I am having trouble figuring this out, so any help would is appreciated
def profile_update(request):
if request.method == "POST":
if u_form.is_valid() and p_form.is_valid():
p_form.instance.user=request.user
p_form.instance.first_name=request.user.first_name
p_form.instance.last_name=request.user.last_name
p_form.instance.email=request.user.email
u_form.save()
p_form.save()
return redirect('mainapp:profile')
context = {
'u_form': u_form,
'p_form': p_form,
}
return render(request, 'mainapp/profile_update.html', context)
Trying to hide a view to create a restaurant from anyone other than a restaurant Owner.
Used examples shown using groups and testing whether a user is in that group or not but nothing seems to work.
views.py
def is_owner(user):
if user.objects.filter(name="Owner").exists():
return True
class CreateRestaurantView(generic.CreateView):
form_class = CreateRestaurantForm
success_url = reverse_lazy('home')
template_name = 'signup.html'
#login_required
def create_restaurant(request):
if is_owner == True:
if request.method == "POST":
form = CreateRestaurantForm(request.POST)
if form.is_valid():
restaurant = form.save(commit=False)
restaurant.Restaurant_Owner = request.user
restaurant.save()
return redirect('restaurant_list')
else:
form = CreateRestaurantForm()
return render(request, 'create_restaurant.html', {'form': form})
else:
return render(request, 'home.html')
forms.py
signup form for Owners
class OwnerCreationForm(forms.ModelForm):
error_messages = {
'password_mismatch': _("The two password fields didn't match."),
}
password1 = forms.CharField(label=_("Password"),
widget=forms.PasswordInput)
password2 = forms.CharField(label=_("Password confirmation"),
widget=forms.PasswordInput,
help_text=_("Enter the same password as above, for verification."))
class Meta:
model = User
fields = ("username",)
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
return password2
def save(self, commit=True):
user = super(OwnerCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
group = Group.objects.get(name='Owner')
user.groups.add(group)
return user
I'm trying to get the view to show the create_restaurant form when a user belongs to the "Owner" group but the function to test (is_owner) does not work and is always false.
First of all, you are defined is_owner as function, so, you should call it as is_owner(any_user_object)
Second thing is, to search over the Group, it should be as
user.groups.filter(name="Owner").exists()
code snippet
def is_owner(user):
return user.groups.filter(name="Owner").exists()
#login_required
def create_restaurant(request):
if is_owner(request.user) == True:
if request.method == "POST":
form = CreateRestaurantForm(request.POST)
if form.is_valid():
restaurant = form.save(commit=False)
restaurant.Restaurant_Owner = request.user
restaurant.save()
return redirect('restaurant_list')
else:
form = CreateRestaurantForm()
return render(request, 'create_restaurant.html', {'form': form})
else:
return render(request, 'home.html')
UPDATE-1
change the save() method of OwnerCreationForm as below
class OwnerCreationForm(forms.ModelForm):
# your other code
def save(self, commit=True):
user = super(OwnerCreationForm, self).save(commit=True)
user.set_password(self.cleaned_data["password1"])
if not user.groups.filter(name="Owner").exists():
group = Group.objects.get(name='Owner')
user.groups.add(group)
user.save()
return user
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
I am doing a basic user creation using the built-in UserCreationForm in Django.
Here is my views.py:
def user_register(request):
if request.method == "POST":
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data['username']
raw_password = form.cleaned_data['password1']
user = User.objects.create_user(username=username)
if raw_password:
user.set_password(raw_password)
else:
user.set_unusable_password()
user.save()
return redirect('home')
else:
form = UserCreationForm()
return render(request, 'registration/register.html', {'form': form})
However, after registering a user and being redirected to home, the number of Users seen in my Admin page has not changed; no User has been created.
Any idea what I am doing wrong here?
Try:
from django.contrib.auth import login, authenticate
from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import render, redirect
from django.contrib.auth.models import User
def user_register(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password1']
user=User.objects.create_user(username=username, password=password)
user.save()
#Below 2 lines, if you want user to get logged in
user = authenticate(username=username, password=password)
login(request, user)
return redirect('home')
else:
form = UserCreationForm()
return render(request, 'registration/register.html', {'form': form})
don't know why you can redirected to home with no use create,but you should deal with the situation form is not vaild and remove form.save() from form.is_valid() block like:
form = UserCreationForm(request.POST)
if form.is_valid():
# remove form.save()
....
else:
print(form.errors.as_text())
return render(request, 'registration/register.html', {'form': form})
or override save method for UserCreationForm like i do:
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
the full demo is:
from django.views.generic import *
class RegisterView(FormView):
template_name = 'registration/register.html'
form_class = UserCreationForm
success_url = reverse_lazy('home')
def form_valid(self, form):
form.save()
return HttpResponseRedirect(self.get_success_url())
forms.py
class UserCreationForm(forms.ModelForm):
error_messages = {
'duplicate_username': u"duplicate username",
'password_mismatch': u"password_mismatch",
'duplicate_email': u'duplicate email'
}
username = forms.RegexField(
max_length=30,
regex=r'^[\w.#+-]+$',
error_messages={
'invalid': u"onlay can contaions symbol #/./+/-/_",
'required': u"required"
},
label='username'
)
email = forms.EmailField(
error_messages={
'invalid': u"email invalid",
'required': u'required'},
label='email'
)
password1 = forms.CharField(
widget=forms.PasswordInput,
error_messages={
'required': u"required"
},
label='password1 '
)
password2 = forms.CharField(
widget=forms.PasswordInput,
error_messages={
'required': u"required"
},
label='password2'
)
def __init__(self, *args, **kwargs):
super(UserCreationForm, self).__init__(*args, **kwargs)
self.fields['username'].widget.attrs.update({'class': 'form-control'})
self.fields['email'].widget.attrs.update({'class': 'form-control'})
self.fields['password1'].widget.attrs.update({'class': 'form-control'})
self.fields['password2'].widget.attrs.update({'class': 'form-control'})
class Meta:
model = User
fields = ("username", "email")
def clean_username(self):
# Since User.username is unique, this check is redundant,
# but it sets a nicer error message than the ORM. See #13147.
username = self.cleaned_data["username"]
try:
User.objects.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError(
self.error_messages["duplicate_username"]
)
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages["password_mismatch"]
)
password_validation.validate_password(password2)
return password2
def clean_email(self):
email = self.cleaned_data["email"]
try:
User.objects.get(email=email)
except User.DoesNotExist:
return email
raise forms.ValidationError(
self.error_messages["duplicate_email"]
)
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
I don't know why you are saving the object so many times. As documented here, when calling form.save() in a UserCreationForm instance, Django will create the user, set the password (which comes from the password1 field), save the instance in the database and return the user for you. So User.objects.create_user and user.save() will only save the object again.
Parhaps it's not the solution for your problem but have you tried just like this:
def user_register(request):
form = UserCreationForm()
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
user = form.save()
# if you want to authenticate your user or log any info, do it here
return redirect('home')
# I wouldn't use the else statement here, so if there are errors in the form you probably want the same template to be rendered, in order to show the form errors to your user.
return render(request, 'registration/register.html', {'form': form})
Thanks for everybody that helped me think this through. It seems, of course, the answer was much simpler than I thought. My new user_register view is:
from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import render, redirect
def user_register(request):
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
return redirect('home')
else:
return render(request, 'registration/register.html', {'form': form})