How to implement password change form in Django 1.9
Solution 1
You can see the Change Password section of following documentation for this. How to change password in Django. It works like this:
Navigation to your project where
manage.py
file lies$ python manage.py shell
-
Execute the following:
from django.contrib.auth.models import User u = User.objects.get(username__exact='john') u.set_password('new password') u.save()
You will have to make a formset and you will perform this action at submission of the form.
You can also use the simple manage.py
command:
manage.py changepassword *username*
Just enter the new password twice.
For second part of your question (User cannot choose old password), you can create a table in which you will store user's old password. When user will enter new password, you can check this in that table whether he can choose it or not. Django has a function check_password which is used to compare two passwords.
Solution 2
why don't you use django's built-in PasswordChangeForm (django.contrib.auth.forms).
If you like the way it works just use this from, or you can create a new one that inherits PasswordChangeForm
class PasswordChangeCustomForm(PasswordChangeForm):
error_css_class = 'has-error'
error_messages = {'password_incorrect':
"Το παλιό συνθηματικό δεν είναι σωστό. Προσπαθείστε ξανά."}
old_password = CharField(required=True, label='Συνθηματικό',
widget=PasswordInput(attrs={
'class': 'form-control'}),
error_messages={
'required': 'Το συνθηματικό δε μπορεί να είναι κενό'})
new_password1 = CharField(required=True, label='Συνθηματικό',
widget=PasswordInput(attrs={
'class': 'form-control'}),
error_messages={
'required': 'Το συνθηματικό δε μπορεί να είναι κενό'})
new_password2 = CharField(required=True, label='Συνθηματικό (Επαναλάβατε)',
widget=PasswordInput(attrs={
'class': 'form-control'}),
error_messages={
'required': 'Το συνθηματικό δε μπορεί να είναι κενό'})
I will provide later an example of the clean and save methods
see here for more details
Solution 3
Easy peasy, if you
from django.contrib.auth.forms import PasswordChangeForm
Then
class MyChangeFormPassword(PasswordChangeForm):
pass
On your view
def get(self, request):
instance_user = get_object_or_404(User, id=int(user_id))
form_edit_password = MyChangeFormPassword(instance_user)
context={'form_edit_password': form_edit_password}
return render(request, self.template_name, context)
On your template
<div class="col-lg-4">
{{form_edit_password.old_password}}
</div>
<div class="col-lg-4">
{{form_edit_password.new_password1}}
</div>
<div class="col-lg-4">
{{form_edit_password.new_password2}}
</div>
And your post
form_edit_password = ChangePasswordForm(user, data=put)
if form_edit_password.is_valid():
form_edit_password.save()
return self.__succes_response(_('Password updated'))
else:
return self.__error_response([form_edit_password])
Django will do everything for you, crazy isn't? You could write your own rules on the MyChangeFormPassword overwriting the parent methods, but this is a great aproach,
I am writing this for Django 3.
Solution 4
Since you are using you custom user model a nice way to implement the functionality is to create a new form ChangePassword
:
class ChangePassword(forms.Form):
old_password=forms.PasswordField()
new_password=forms.PasswordField()
reenter_password=forms.PasswordField()
def clean(self):
new_password=self.cleaned_data.get('new_password')
reenter_password=self.cleaned_data.get('reenter_password')
#similarly old_password
if new_password and new_password!=reenter_password or new_password==old_password:
#raise error
#get the user object and check from old_password list if any one matches with the new password raise error(read whole answer you would know)
return self.cleaned_data #don't forget this.
You can define clean()
to check that both passwords match or not, and also the new password entered is not same as the old password.
If you don't want the user to use a password they have used before an option would be
- Create a new field (if you want to store these passwords as plain strings)
- Create a model containing hashed previous passwords (for better security).
According to your models you are not encrypting passwords so option 1 is good for you. In case you want to encrypt you can choose sha256 for it, library is passlib; just search google.
To implement option 1 just add a field to your model and whenever password is changed, append the old password to this field contents. You can either use a CharField
but its maximum length is only 255 instead you can choose textfield
, for your model it would be like:
class Members(models.Model):
#rest fields..
old_passwords=models.TextField(blank=True,default='')
Now when saving ChangePassword use the cleaned data to update the member password:
def change_password(request):
if request.method=='POST':
form=ChangePassword(request.POST)
if form.is_valid():
new_pass=form.cleaned_data['new_password']
#get the current user object as user
if user.old_password=='':
#it's first time user is changing password
#populate our Members old_password_field
user.old_password=user.password
else:
user.old_password=user.old_password+','+user.password
user.password=new_password
user.save()
#do whatever you want to do man..
The code is just to help you understand what you need to do, you have to do thing your own way!
Solution 5
IN urls.py
path('password-reset/', views.ChangePassword.as_view(), name='password-reset'),
Password change form:
class MyPasswordChangeForm(PasswordChangeForm):
def __init__(self, user, *args, **kwargs):
self.user = user
super().__init__(user, *args, **kwargs)
self.fields['old_password'].widget.attrs.update({'class': 'form-control', 'placeholder': "Old Password"})
self.fields['new_password1'].widget.attrs.update({'class': 'form-control', 'placeholder': "New Password"})
self.fields['new_password2'].widget.attrs.update({'class': 'form-control', 'placeholder': "New Password"})
def save(self, commit=True):
password = self.cleaned_data["new_password1"]
self.user.set_password(password)
if commit:
self.user.save()
return self.user
In views.py:
from django.views.generic import TemplateView
from django.contrib.auth.mixins import LoginRequiredMixin
class ChangePassword(LoginRequiredMixin,TemplateView):
def get(self, request, *args, **kwargs):
form_class = MyPasswordChangeForm
form = self.form_class(self.request.user)
return render(request, 'password.html',{'form': form,})
def post(self, request, *args, **kwargs):
form = self.form_class(request.user, request.POST)
if form.is_valid():
user = form.save()
update_session_auth_hash(request, user) # Important!
return render(request, 'password.html', {'form': form, 'password_changed': True})
else:
return render(request, 'password.html', {'form': form, 'password_changed': False})
In password.html:
<div id='PasswordChnageForm'>
<form method="post" action="{% url 'password-reset' %}">
{% csrf_token %}
{% for field in form %}
{{ field }}
{% if field.help_text %}
<small style="display: none">{{ field.help_text }}</small>
{% endif %}
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
{% endfor %}
<input type="submit" name="save" value="Save" >
</form>
</div>
<script src="{% static 'web_admin/js/jquery-3.4.1.min.js' %}"></script>
<script>
$("#CallPasswordChangeButton").on('click', function (e) {
e.preventDefault(); // avoid to execute the actual submit of the form.
var form = $('#PasswordChnageForm');
$.ajax({
type: 'Post',
url: "{% url 'password-reset' %}",
data: form.serialize(),
success: function (data) {
$('#password_change').empty().html(data);
}
});
});
</script>
![Admin](/assets/logo_square_200-5d0d61d6853298bd2a4fe063103715b4daf2819fc21225efa21dfb93e61952ea.png)
Admin
Updated on October 26, 2021Comments
-
Admin over 2 years
The url for my python project is here: https://github.com/abylikhsanov/social
I am trying to implement the password change form, so the user can change his or her password. How can I implement it? The application should keep track of the previous password and should not allow the user to use a previously used password. Also, I want to implement the reset password function.
-
Admin over 8 yearsSo template_name - should be my custom template for reseting the password? The link you've provided, will it be enough to use the example template?
-
Admin over 8 yearsDid you mean old_password=forms.PasswordInput()? As mine cant resolve yours
-
Admin over 8 yearsAlso, what does the "user" means here? Do I need to create a separate class for storing users?
-
Admin over 8 yearsAlso, the 'return self.cleaned_data ' gives me "return outside of function"
-
rdRahul over 8 yearsyes, it was forms.PasswordInput(), and user object means your Member's class object , return should work fine try reading from here docs.djangoproject.com/en/1.9/ref/forms/validation
-
Greg Schmit about 7 yearsThis doesn't seem to answer the question. The OP wants to have a change password form (and view/template), along with password history.
-
Muhammad Hassan about 7 years@GregSchmit The answer of functionality which he is asking will be very long in my opinion. That is why I did not write the whole code. Instead I wrote how can he solve his problem.
-
Greg Schmit about 7 yearsI agree that it is a broad, poorly-put question.