27

I was having trouble with FormView recently and found that the way to go about doing it was to use get_form_kwargs.

Here is my code:

class InternalResetPasswordView(FormView):

template_name = 'reset_password.html'
form_class = forms.InternalPasswordResetForm

# success_message = "Password was reset successfully"

# To get request object
# http://notesondjango.wordpress.com/2012/12/18/modelform-formview-and-the-request-object/
# https://stackoverflow.com/questions/13383381/show-message-after-password-change
# http://pydanny.com/simple-django-email-form-using-cbv.html
# http://bubuzzz.wordpress.com/2012/05/01/class-based-generic-views-in-django-a-simple-sample/
def get_form_kwargs(self):
    kwargs = super(InternalResetPasswordView, self).get_form_kwargs()
    kwargs['user'] = self.request.user
    return kwargs

def get_success_url(self):
    return reverse('user-detail', kwargs={'pk': self.request.user.id})

@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
    return super(InternalResetPasswordView, self).dispatch(*args, **kwargs)   

'''
def get_context_data(self, **kwargs):

    context = super(InternalResetPasswordView, self).get_context_data(**kwargs)
    context['InternalPasswordResetForm'] = context.get('form')

    return context


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

'''
# self.request.user method obtained from
# https://docs.djangoproject.com/en/dev/topics/class-based-views/generic-editing/
def form_valid(self, form):
    current_password = form.cleaned_data['old_password']
    new_password =  form.cleaned_data['new_password1']
    confirm_new_password = form.cleaned_data['new_password2']
    user = self.request.user
    if user.check_password(current_password) and new_password == confirm_new_password:
        user.set_password(new_password)
        user.save()
        # form.valid() redirects to get_success_url
    return super(InternalResetPasswordView, self).form_valid(form)

After looking at this post, I still don't understand why get_form_kwargs has to be used and why using self.request instead of self.request.user in this case gives __init__() got an unexpected keyword argument 'request'.

Could someone explain this to me?

Thanks for all the help :)

Community
  • 1
  • 1
a_technicolor_skye
  • 283
  • 1
  • 3
  • 5

1 Answers1

35

The get_form_kwargs method will return a dictionary with the kwargs that will be passed to the __init__ of your form. Now, if you have a form that expects a kwarg named user and pass it a kwarg named request it will complain with the error you see. If you want to pass request instead of user (this is what I usually do since the request contains the user) then you should define your form class like this:

class RequestForm(forms.Form):
    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request', None)
        super(RequestForm, self).__init__(*args, **kwargs)
Serafeim
  • 14,962
  • 14
  • 91
  • 133
  • Could you tell me how does my form expect `request` from my code as I could just define it as: `def get_form_kwargs(self): kwargs = super(InternalResetPasswordView, self).get_form_kwargs() kwargs['request'] = self.request return kwargs`. Sorry about the formatting, can't seem to get line breaks to work. – a_technicolor_skye Sep 04 '13 at 06:31
  • 4
    With the ```def get_form-kwargs(self)``` method you are not defining a Form, you are just defining which kwargs will pass your View tothe Form! A django Form expects specific kwargs. If you try to pass it something that is not expected it will complain. That's why you have to call kwargs.pop() to remove the request you want to use in your Form implementation before calling ```super().__init___```. – Serafeim Sep 04 '13 at 06:40
  • Since FormView instantiates a form, how does it not take `request` as an argument? Noob question here >. – a_technicolor_skye Sep 04 '13 at 08:06
  • 1
    In your ```InternalResetPasswordView``` you are passing a ```form_class = forms.InternalPasswordResetForm```. So your FormView will need to instantiate an ```InternalPasswordResetForm``` instance and will pass to the ```__init___``` of that the result of the get_form_kwargs() method! So in your ```InternalPasswordResetForm``` you have to remove any extra arguments from the kwargs dictionary before passing it to the super.__init__ ! The error is not with your ```FormView``` implementation but with your ```Form``` ! – Serafeim Sep 04 '13 at 08:16