SetPasswordForm - changes password, but login fails :(

Apologies, I’m new to Django, so this might be super obvious.

I’m trying to test the user change-password functionality on my webapp.
I can see that the password has successfully changed when I login as admin and look at the relevant user-id (the redacted salt and hash values both change). However, I’m unable to login with the new user credentials (username and password mismatch). The password encryption algorithm hasn’t changed (pbkdf2_sha256) - so I’m not sure where it’s going wrong.

Below is a snippet of the relevant part of the code:

uid = force_str(urlsafe_base64_decode(uidb64))
user = MyUser.objects.get(pk=uid)

# ...

form = SetPasswordForm(user,request.POST)
if form.is_valid():
    user = form.save(commit=False)
    print('user = ' + str(user))
    print(form.cleaned_data.get("new_password1"))
    user.save()

The print statements above show exactly what I was expecting (i.e. the test username and the new password are printed).

Is this something to do with me creating a new user model MyUser rather than the Django out of the box? Since SetPasswordForm takes user as an argument, I assumed all would be well.

Any help greatly appreciated. Also, if anyone knows of any solid examples I could look at of the Django authentication used in practice, I’d love to take a look. The docs are a bit dry in this area.

cheers,
Paul

You can use user.set_password(password) in order to set password received from form data and then user.save() to save the instance.

To add to @addwebsolution’s answer above, the best examples of Django authentication in practice would be to look at Django’s own authentication views in django.contrib.auth.views, along with the forms in django.contrib.auth.forms.

2 Likes

Thanks for that @addwebsolution and @KenWhitesell. I’ll have a go doing set_password explicitly.
But - how is that different to what SetPasswordForm is doing? According to the source code it’s just doing set_password anyway. Am I missing something?


def save(self, commit=True):
        self.user.set_password(self.cleaned_data['new_password1'])
        if commit:
            self.user.save()
        return self.user

Side note: the line:

is creating an instance of the SetPasswordForm object. It’s not, of its own, doing anything with the data other than populating the object with what was submitted from the browser.

It’s the line:

that should be causing the save method to update the password.

Now, the key point that I missed was:

By this, you’re trying to use a custom user model?

If so, did you make the settings change to AUTH_USER_MODEL?

Are you using a customized login view/form?

Yes, I knew that much :slight_smile:

Yes - the Django tutorial I was following suggested that it’s always good practice to create your own user model (but didn’t really explain why).

I have set AUTH_USER_MODEL in settings.py.

To be clear - I can create new users and login fine via this same user model, it’s only when I try to save a new password that it falls over. This is why I was scratching my head.

Ah, I’m an idiot.

I re-ran migrations and now everything is working as expected. Works via form.save and via user.set_password.

Apologies - I mist have made some changes to the user model without migrating everything.

1 Like

No worries - we’ve all been there.

1 Like

Thanks for the super-fast advice!