[Django]-How to implement password change form in Django 1.9

8👍

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

7👍

You can see the Change Password section of following documentation for this. How to change password in Django.
It works like this:

  1. Navigation to your project where manage.py file lies

  2. $ python manage.py shell

  3. 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.

4👍

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.

3👍

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

  1. Create a new field (if you want to store these passwords as plain strings)
  2. 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!

1👍

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>
        $("#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>

0👍

actually you can use Django forms , they have built-in form called"PasswordChangeForm" and you can import it from "django.contrib.auth.forms"

but for me i always like to use a pure html form and build my views.py function step by step like the following example :

html form :

<div class="col-md-6">

    <form method="POST">
        {% csrf_token %}

    <div class="form-group">
        <label for="exampleInputPassword1">Old Password</label>
        <input type="password" name="q_Old_Password" class="form-control" id="exampleInputPassword1" placeholder="Password">
    </div>


    <div class="form-group">
        <label for="NewPassword">New Password</label>
        <input type="password" name="q_new_Password" class="form-control" id="NewPassword" placeholder="Password">
    </div>


    <div class="form-group">
        <label for="ConfirmNewPassword">Confirm New Password</label>
        <input type="password" name="q_confirm_new_Password" class="form-control" id="ConfirmNewPassword" placeholder="Password">
    </div>

    <button type="submit" class="btn btn-primary">Submit</button>
    </form>
</div>

and here is views.py function :

from django.contrib.auth.models import User
from django.contrib.auth import update_session_auth_hash

def change_password(request):

    if request.method == 'POST':
        old_password = request.POST.get("q_Old_Password")
        new_password = request.POST.get("q_new_Password")
        confirmed_new_password = request.POST.get("q_confirm_new_Password")

        if old_password and new_password and confirmed_new_password:
            if request.user.is_authenticated:
                user = User.objects.get(username= request.user.username)
                if not user.check_password(old_password):
                    messages.warning(request, "your old password is not correct!")
                else:
                    if new_password != confirmed_new_password:
                        messages.warning(request, "your new password not match the confirm password !")
                    
                    elif len(new_password) < 8 or new_password.lower() == new_password or \
                         new_password.upper() == new_password or new_password.isalnum() or \
                         not any(i.isdigit() for i in new_password):
                        messages.warning(request, "your password is too weak!")

                    

                    else:
                        user.set_password(new_password)
                        user.save()
                        update_session_auth_hash(request, user)

                        messages.success(request, "your password has been changed successfuly.!")

                        return redirect('dashboard_namespace:home')

        else:
            messages.warning(request, " sorry , all fields are required !")
 


    context = {

    }
    return render(request, "pages/users_accounts/change_password.html", context)

i hope this helpful.

👤K.A

-1👍

if you take a look at https://github.com/django/django/blob/master/django/contrib/auth/views.py
you will notice that

password_reset

takes a named parameter called

template_name

def password_reset(request, is_admin_site=False, 
        template_name='registration/password_reset_form.html',
        email_template_name='registration/password_reset_email.html',
        password_reset_form=PasswordResetForm, 
        token_generator=default_token_generator,
        post_reset_redirect=None):

thus with urls.py like…

from django.conf.urls.defaults import *
from django.contrib.auth.views import password_reset
urlpatterns = patterns('',
 (r'^/accounts/password/reset/$', password_reset, {'template_name': 'my_templates/password_reset.html'}),
 ...

django.contrib.auth.views.password_reset will be called for URLs matching ‘/accounts/password/reset’ with the keyword argument template_name = ‘my_templates/password_reset.html’.

i strongly recommend you to go through the following link
http://garmoncheg.blogspot.com.au/2012/07/django-resetting-passwords-with.html

Leave a comment