Class Based Views Form neither Valid nor Invalid (Django)

Viewed 43

I'm new to Django Class Based Views and I can't get my form to pass through neither form_valid() nor form_invalid().

I have taken most of this code from the Django allauth module, so I extend some mixins (AjaxCapableProcessFormViewMixin & LogoutFunctionalityMixin) that I do not know well.

This form is meant to allow users to change their passwords upon receiving an email. As it is now, users are able to change their password but since the form_valid() function is never triggered, they do no get redirected to the success URL as is intended. Instead the password change is registered but the users stay on the same page.

The functions dispatch(), get_form_kwargs() & get_form_class() are all triggered and behave in the way that they should. Still, it's unclear to me why they execute in the order that they do (dispatch() is triggered first, then get_form_class() and finally get_form_kwargs(). I suppose they implicitely have an order as presented in this documentation: https://ccbv.co.uk/projects/Django/4.0/django.views.generic.edit/FormView/)

I am lacking some intuition about how this works, therefore I don't know if there is a way to redirect to the success URL without passing through form_valid() because that would also solve my problem.

As is mentionned in the title, neither form_valid() nor form_invalid() is triggered after submitting a new password. The last executed bit of code is the return kwargs from the get_form_kwargs() function.

Here is my code:

class PasswordResetFromKeyView(AjaxCapableProcessFormViewMixin, LogoutFunctionalityMixin, FormView):
    template_name = "account/password_reset_from_key." + app_settings.TEMPLATE_EXTENSION
    form_class = ResetPasswordKeyForm
    success_url = '/'
    reset_url_key = "set-password"

    def get_form_class(self):
        return get_form_class(
            app_settings.FORMS, "reset_password_from_key", self.form_class
        )

    def dispatch(self, request, uuid, **kwargs):
        self.request = request

        token = get_object_or_404(ResetToken, token=uuid)

        if token.redeemed == False:
            self.reset_user = token.client
            self.token = token
            response = self.render_to_response(self.get_context_data(token_fail=False))
        else:
            return super(PasswordResetFromKeyView, self).dispatch(
                    request, uuid, **kwargs
                )
        return response


    def get_form_kwargs(self, **kwargs):
        kwargs = super(PasswordResetFromKeyView, self).get_form_kwargs(**kwargs)
        kwargs["user"] = self.reset_user
        if len(kwargs) > 3:
            try:
                if kwargs['data']['password1'] == kwargs['data']['password2']:
                    self.reset_user.set_password(kwargs['data']['password1'])
                    self.reset_user.save()
                    self.token.redeemed = True
                    self.token.date_redeemed = datetime.now()
                    self.token.save()
                    perform_login(
                        self.request,
                        self.reset_user,
                        email_verification=app_settings.EMAIL_VERIFICATION,
                    )
                else:
                    pass
                    ##passwords dont match
            except:
                ##couldnt change the password
                pass
        return kwargs

    def form_valid(self, form, **kwargs):
        form.save()
        return super(PasswordResetFromKeyView, self).form_valid(form)

    def form_invalid(self, form):
        response = super().form_invalid(form)
        if self.request.accepts('text/html'):
            return response
        else:
            return JsonResponse(form.errors, status=400)
1 Answers

If both methods are not triggered, it means - you requests.method is never is 'POST'.

The class FormView calls this two methods only if post.method == 'POST':

# code from django.views.generic.edit
...
def post(self, request, *args, **kwargs):
    """
    Handle POST requests: instantiate a form instance with the passed
    POST variables and then check if it's valid.
    """
    form = self.get_form()
    if form.is_valid():
        return self.form_valid(form)
    else:
        return self.form_invalid(form)

By the way in dispatch, if token.redeemed == False you should return self.form_invalid().

Related