I'm trying to create an "Edit Profile" form in the fronted. What happens is that my form(i'm not 100% sure) tries to create a user instead of finding the current user and update his profile. So I think that's the issue. Checked many questions here but none was clear enough. The fields I'm trying to edit are email(to be checked if email already exisit), Name, user type, and password.
below is the code for forms.py
class ProfileForm(forms.ModelForm):
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Confirm Password', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('full_name', 'active', 'admin','email','user_type')
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(ProfileForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
# user.active = False # send confirmation email
if commit:
user.save()
return user
code for views.py
def profile(request):
user = User.objects.filter(email = request.user)
# form = ProfileForm(user.values().first())
if request.method == 'POST' :
form = ProfileForm(request.POST)
if form.is_valid():
form.save(commit=True)
form = ProfileForm(user.values().first())
# print(user)
context = {
'object_list': user,
'form': form
}
return render(request, 'userpanel/profile.html',context)
Thanks in advance
You didn't pass instance argument to the form. Without instance it will try to create new object. It should be like this:
form = ProfileForm(request.POST, instance=user)
Also you don't need to query user with this: user = User.objects.filter(email = request.user). Just add login_requred decorator to ensure user is authenticated and use request.user:
from django.contrib.auth.decorators import login_required
#login_required
def profile(request):
if request.method == 'POST' :
form = ProfileForm(request.POST, instance=request.user)
Related
good day!A separate page was created to change the password, when you enter the password and repeat it and click on the "change password" button, a duplicate key value violates unique constraint "core_user_username_key" error appears
DETAIL: key (username) = already exists
how to solve this error?
forms.py
class CallcenterPasswordChange(forms.ModelForm):
password1 = forms.CharField(widget=forms.PasswordInput(), label='Новый пароль')
password2 = forms.CharField(widget=forms.PasswordInput(), label='Повтор нового пароля')
def clean(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='Повтор нового пароля не совпадает',
)
return self.cleaned_data
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'password1', 'password2')
views.py
class CallcenterPasswordChangeView(AbsCallcenterView):
template_name = 'callcenter/password_change.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
patient_pk = kwargs.get('patient_pk')
patient = get_object_or_404(Patient, pk=patient_pk)
initial_data = model_to_dict(patient.user)
context['form'] =CallcenterPasswordChange(initial=initial_data)
context['patient_pk'] = patient_pk
context['patient'] = patient
return context
def post(self, request, **kwargs):
context = super().get_context_data(**kwargs)
patient_pk = kwargs.get('patient_pk')
patient = get_object_or_404(Patient, pk=patient_pk)
form = CallcenterPasswordChange(request.POST)
context['form_user'] = form
context['patient'] = patient
if form.is_valid():
form.save()
else:
return render(request, template_name=self.template_name, context=context)
This isn't what you want to do at all. What this is trying to do is to create a completely new user.
What's more, the password1 and password2 fields are not associated with the actual password field in the model; plus, there is nothing that takes care of hashing the password.
What you actually want is a standard (non-model) form with just those two fields, and then to set the password of the current user.
So the form is just:
class CallcenterPasswordChange(forms.Form):
password1 = forms.CharField(widget=forms.PasswordInput(), label='Новый пароль')
password2 = forms.CharField(widget=forms.PasswordInput(), label='Повтор нового пароля')
def clean(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='Повтор нового пароля не совпадает',
)
return self.cleaned_data
and in the view, you do:
form = CallcenterPasswordChange(request.POST)
if form.is_valid():
request.user.set_password(form.cleaned_data['password1'])
request.user.save()
return redirect('somewhere')
However, you should also note that Django includes a password change form and view already.
problem solved!
class CallcenterPasswordChangeView(AbsCallcenterView):
template_name = 'callcenter/password_change.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
patient_pk = kwargs.get('patient_pk')
patient = get_object_or_404(Patient, pk=patient_pk)
initial_data = model_to_dict(patient.user)
context['form'] = CallcenterPasswordChange(initial=initial_data)
context['patient'] = patient
return context
def post(self, request, **kwargs):
context = super().get_context_data(**kwargs)
patient = Patient.objects.get(pk=context['patient_pk'])
form = CallcenterPasswordChange(request.POST)
context['form'] = form
if form.is_valid():
patient.user.set_password(form.cleaned_data['password1'])
patient.user.save()
success_url = reverse_lazy('callcenter:patients')
return HttpResponseRedirect(success_url)
I've searched everywhere for a solution to this problem. Yet, no resolution as of yet.
The problem
After successfully creating a user via a front-end registration form, upon logging in using a front-end login form, the "Authenticate" function returns "None".
The interesting part, if I am to create a new user via the admin panel (using similar code), I am then able to login via the front-end login form.
The custom user model I've created does use an email address as the Username. If a user registers using the front-end register form, the user details are saved to the database, where the password is properly hashed.
Here is the code:
From Forms.py
from django import forms
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from .models import User as CustomUser
from django.conf import settings
class RegisterForm(forms.ModelForm):
password1 = forms.CharField(label='', widget=forms.PasswordInput)
password2 = forms.CharField(label='', widget=forms.PasswordInput)
class Meta:
model = CustomUser
fields = ('email', 'full_name')
def __init__(self, *args, **kwargs):
super(RegisterForm, self).__init__(*args, **kwargs)
self.fields['email'].widget.attrs.update(
{'class': 'form-control loginInput', 'placeholder': 'Your Email (you#company.com)'})
self.fields['full_name'].widget.attrs.update(
{'class': 'form-control loginInput', 'placeholder': 'Your Full Name'})
self.fields['email'].label = ''
self.fields['full_name'].label = ''
self.fields['password1'].widget.attrs.update(
{'class': 'form-control loginInput', 'placeholder': 'Your Password'})
self.fields['password2'].widget.attrs.update(
{'class': 'form-control loginInput', 'placeholder': 'Confirm Password'})
def clean_email(self):
email = self.cleaned_data.get('email')
qs = CustomUser.objects.filter(email=email)
if qs.exists():
raise forms.ValidationError("email is taken")
return email
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Saving the provided password in hashed format
user = super(RegisterForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserAdminCreationForm(forms.ModelForm):
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
class Meta:
model = CustomUser
fields = ('email',)
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("Passwords don't match")
return password2
def save(self, commit=True):
user = super(UserAdminCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
From Views.py
def register(request):
registered = False
if request.method == 'POST':
registration = forms.RegisterForm(data=request.POST)
if registration.is_valid():
member = registration.save()
member.set_password(member.password)
member.save()
registered = True
else:
print(registration.errors)
else:
registration = forms.RegisterForm()
print("Registered: " + str(registered))
return render(request, 'accounts/registration.html',
{'registration_form': registration,
'registered': registered,
})
def user_login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username=username, password=password)
if user not None:
if user.is_active:
login(request, user)
return HttpResponseRedirect(reverse('account_index'))
else:
HttpResponse("ACCOUNT NOT ACTIVE")
else:
print("Someone tried to login and failed!")
print("Email: {} and password {}".format(username, password))
return HttpResponse("invalid login details supplied!")
else:
return render(request, 'accounts/user_login.html', {})
I'm at a loss at the present time. Could use some direction or advice.
Ok, I've resolved this issue. It seems as though I just needed to sleep on it.
Here is the code that was causing the issue:
In Views.py
member.set_password(member.password)
It seems as if though it was setting a hashed version of the password. But "set_password" must be the raw version of the password.
To fix this I changed it to:
member.set_password(request.POST.get('password1'))
Behold, it works!
I'm using a view to create new users in Django. And then I have another view to log them in.
But when I create a user, and I try to log in with authenticate(username=username_post, password=password_post), I get None, so it displays in the template 'Wrong username or password.'.
In my database, I see new registers every time I create a new user. However, as the password is encrypted, I can't say if the problem is the login view, or the register view.
However, the super user that I created through the command line after I first installed django, is able to login with no problem, so that makes me thing that the problem is when I create the user.
These are my Login and Register views:
class Login(View):
form = LoginForm()
message = None
template = 'settings/blog_login.html'
def get(self, request, *args, **kwargs):
if request.user.is_authenticated():
return redirect('settings:index')
return render(request, self.template, self.get_context())
def post(self, request, *args, **kwargs):
username_post = request.POST['username']
password_post = request.POST['password']
user = authenticate(username=username_post, password=password_post)
if user is not None:
login(request, user)
return redirect('settings:index')
else:
self.message = 'Wrong username or password.'
return render(request, self.template, self.get_context())
def get_context(self):
return {'form': self.form, 'message': self.message}
class Register(CreateView):
success_url = reverse_lazy('settings:login')
model = User
template_name = 'settings/blog_register.html'
form_class = RegisterForm
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.set_password(self.object.password)
self.object.save()
return HttpResponseRedirect(self.get_success_url())
And these are my forms:
class LoginForm(forms.Form):
username = forms.CharField(max_length=20, label='Username')
password = forms.CharField(label='Password', widget=forms.PasswordInput())
class RegisterForm(forms.ModelForm):
username = forms.CharField(max_length=20, label='Username')
password1 = forms.CharField(label='Password', widget=forms.PasswordInput(),
error_messages={'required': 'Required field.',
'unique': 'Username already used.',
'invalid': 'Not valid username.'})
password2 = forms.CharField(label='Retype password', widget=forms.PasswordInput(),
error_messages={'required': 'Required field.'})
email = forms.EmailField(error_messages={'required': 'Required field.',
'invalid': 'Invalid email.'})
def clean(self):
clean_data = super(RegisterForm, self).clean()
password1 = clean_data.get('password1')
password2 = clean_data.get('password2')
if password1 != password2:
raise forms.ValidationError('Passwords are different.')
return self.cleaned_data
def clean_email(self):
email = self.cleaned_data.get('email')
username = self.cleaned_data.get('username')
if email and User.objects.filter(email=email).exclude(
username=username).exists():
raise forms.ValidationError('Email already used.')
return email
class Meta:
model = User
fields = ('username', 'password1', 'password2', 'email')
Please, let me know if you need more info.
You don't have a field called 'password' in your form - you just have 'password1' and 'password2' - so nothing is saved to the model object's actual password field. So, when you do self.object.set_password(self.object.password), you're actually setting a blank password.
Instead, you should get the value from your form's password1 field:
self.object.set_password(self.form.cleaned_data['password1'])
I have a UserProfile model to add some things to my User model and one thing I want to do is have unique email for users so I added an email attribute to my UserProfile model and set it to unique=True like this :
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name="profile")
email = models.EmailField(unique=True)
avatar = models.ForeignKey(Avatar)
...
I created a custom form for the registration to add some infos directly to my UserProfile :
class CreateUserForm(forms.Form):
username = forms.CharField(max_length=30, label="Pseudo")
password1 = forms.CharField(widget=forms.PasswordInput, label="Password")
password2 = forms.CharField(widget=forms.PasswordInput, label="Confirmez pwd")
email = forms.EmailField(widget=forms.EmailInput, label="E-mail")
avatar = AvatarChoiceField(widget=forms.RadioSelect, queryset=Avatar.objects.all(), label="Avatar")
def clean_username(self):
username = self.cleaned_data.get('username')
if User.objects.filter(username=username).exists():
raise forms.ValidationError("This username is already used")
return username
def clean_password2(self):
password1 = self.cleaned_data.get('password1')
password2 = self.cleaned_data.get('password2')
if password1 != password2:
raise forms.ValidationError("Your passwords do not match")
return password1
def clean_email(self):
email = self.cleaned_data.get('email')
if UserProfile.objects.filter(email=email).exists():
raise forms.ValidationError("This email is already used")
return email
And then in my views.py I treat my form like that :
def create_user(request):
if request.method == 'POST':
form = CreateUserForm(request.POST)
if form.is_valid():
username = form.clean_username()
email = form.clean_email()
password = form.clean_password2()
username = form.cleaned_data['username']
avatar = form.cleaned_data['avatar']
user = User.objects.create_user(username=username, password=password)
user.save()
user_profile = UserProfile(user=user, email=email, avatar=avatar)
user_profile.save()
else:
form = CreateUserForm()
return render(request, 'accounts/create.html', locals())
Finally I used the email of the form for my UserProfile model and not for my User model. And by this way I have a unique email for my users. And it's working.
Am I doing it right or is there a better way to achieve what I want ?
You are on the right track, the only thing that doesn't look right is that you shouldn't call clean method manually like this:
# These are not needed in your view method
username = form.clean_username()
email = form.clean_email()
password = form.clean_password2()
They are already called by form.is_valid(). See this SO question for details.
I'm trying to create edit user profile functionality. But I get the following error. I feel like it's trying to create a new user instead of editing the existing one. So that might result into username not being unique. I've no idea what to change/add here.
Here is my views
def showProfile(request, id):
profile = DoctorSeeker.objects.get(id=id)
return render(request,'meddy1/seekerprofile.html',{'doctorSeeker': profile})
def update_profile(request):
args = {}
if request.method == 'POST':
form = UserUpdateForm(request.POST)
if form.is_valid():
form.save()
return render(request, showProfile())
else:
form = UserUpdateForm()
args['form'] = form
return render(request, 'meddy1/editseekerprofile.html', args)
Here is my forms
class UserUpdateForm(forms.ModelForm):
name = forms.CharField(max_length=200, widget=forms.TextInput(attrs={'class': 'form-control','placeholder':'FirstName LastName'}))
email = forms.EmailField(required=True, widget=forms.TextInput(attrs={'class': 'form-control','placeholder':'Please enter a valid email address so we can reach you. No spam. Ever.'}))
password1 = forms.CharField(label="Old Password",widget=forms.PasswordInput(attrs={'class': 'form-control','placeholder':'Enter your password to save the changes.'}),required=False)
password2 = forms.CharField(label="New Password?",widget=forms.PasswordInput(attrs={'class': 'form-control','placeholder':'Only enter new password if you want to change it.'}),required=False)
password3 = forms.CharField(label="Confirm New Password",widget=forms.PasswordInput(attrs={'class': 'form-control','placeholder':'Confirm New Password'}),required=False)
class Meta:
model = DoctorSeeker
fields = ("name","email")
class Meta:
model = User
fields = ("password2", "password3")
def clean_password2(self):
password2 = self.cleaned_data.get("password2")
password3 = self.cleaned_data.get("password3")
if password2 and password3 and password2 != password3:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
return password2
def save(self, commit=True):
user = super(UserUpdateForm, self).save(commit=False)
user.set_password(self.cleaned_data["password2"])
fullName = self.cleaned_data["name"]
Email = self.cleaned_data["email"]
if commit:
user.save()
userProfile = DoctorSeeker(user=user, name=fullName, email=Email)
userProfile.save()
return user
the save method of django form will create a new object (if no instance are suplied) and not an update of this one. You have to retreive your user first pass the instance through the form and then save it.
For more informations see: https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#the-save-method