Nrzonline
Nrzonline

Reputation: 1618

can't pass 'user' parameter to ChangePasswordForm in django

Good day SO!

I'm learning Django (1.8) with class-based-views. Django itself provides an authentication module with the possibility to change the user's password. While using the Django's PasswordChangeForm (which extends Django's SetPasswordForm), I stumble upon the following error:

init() missing 1 required positional argument: 'user'

When I take a look at SetPasswordForm class, I can see it requires an user-object as parameter.

def __init__(self, user, *args, **kwargs):
    self.user = user
    super(SetPasswordForm, self).__init__(*args, **kwargs)


What did I initially do?
First off, in my view I simply assigned the Django's PasswordChangeForm:

class ChangePassword(LoginRequiredMixin, FormView):
    template_name = 'users/reset_password.html'
    form_class = PasswordChangeForm

Which led to the error of course, because no user-object has been provided.

So what have I attempted to solve this issue?

Attempt one: Custom form which inherits from PasswordChangeForm and adds the init method.
Since the PasswordChangeForm does not have an init method, I crated a new form class called MyPasswordChangeForm, which inherits from PasswordChangeForm and adds the init:

class MyPasswordChangeForm(PasswordChangeForm):
    def __init__(self, request, *args, **kwargs):
        super(MyPasswordChangeForm, self).__init__(request.user, *args, **kwargs)

Expected result: MyPasswordChangeForm->inherit from PasswordChangeForm and add init->super init->perform init in SetPasswordForm
Actual result: super is calling the LoginRequiredMixin:

init() missing 1 required positional argument: 'request'
stack-tr l:80 return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)

Attempt 'two': minor changes Changing super->MyPasswordChangeFrom to super->PasswordChangeForm

Attempt three: using a mixin, but had same result as above unfortunately.

Attempt four: not done this yet, but would be the final option? But there must be a way to use the django's forms as much as possible.

So my question is... Can somebody give a hint or small explanation on how I can pass the (authenticated) user-object to the Django's SetPasswordForm via Django's PasswordChangeForm, so I can use as much as possible of the currently existing forms.

Thanks in advance!

Upvotes: 0

Views: 1090

Answers (1)

Andrei Avram
Andrei Avram

Reputation: 948

request isn't sent by default to the FormView upon initialization. You have to sneak it in there somehow.

Based on your attempt #1, a good way to do this is overriding the method get_form_kwargs() in your FormView, and add request as a key to the dict it's super already provides. Then, use the kwargs in MyPasswordChangeForm's __init__ to get request.

Esentially, you'd do something like:

class ChangePassword(LoginRequiredMixin, FormView):
    template_name = 'users/reset_password.html'
    form_class = PasswordChangeForm

    def get_form_kwargs(self, **kwargs):
        data = super(ChangePassword, self).get_form_kwargs(**kwargs)
        data['request'] = self.request
        return data

And then, in your Form's init:

def __init__(self, *args, **kwargs):
    request = kwargs.pop("request") # it's best you pop request, so that you don't get any complains for a parent that checks what kwargs it gets
    super(MyPasswordChangeForm, self).__init__(request.user, *args, **kwargs)

Upvotes: 5

Related Questions