Search code examples
djangodjango-class-based-viewsformviewkeyword-argument

Passing data to FormView form Form via kwargs


I've been struggling to pass some extra data form my Form class to my views. For a password recovery an user has to fill in an username or e-mail address. When cleaning, the username and password are checked if one of them exists in the database:

def clean(self):
    username = self.cleaned_data.get("username")
    email = self.cleaned_data.get("email")

    if username:
        try:
            user = User.objects.get(username__iexact=username, is_active=True) # <- to view

        except User.DoesNotExist:
            raise forms.ValidationError(
                self.error_messages["invalid_username"],
                code="invalid_username"
            )
    elif email:
        try:
            user = User.objects.get(email__iexact=email, is_active=True) # <- to view

        except User.DoesNotExist:
            raise forms.ValidationError(
                self.error_messages["invalid_email"],
                code="invalid_email"
            )
    else:
        raise forms.ValidationError(
            self.error_messages["empty_form"],
            code="empty_form"
        )
    return self.cleaned_data

When the form has been validated, I want to send the user data to the view. This to separate the send_email logics away from the form and being able to add some information to the context, so it can be rendered in the template.

So in my FormView, if the form is valid, I want to be able to use the user object retrieved in the Form.

Currently I have attempted quite some 'answers' of other SO questions and examples of the web. But I keep getting AttributeErrors, KeyErrors, 'WSGIRequest' object does not support item assignment.

The last attempt I made was to overwrite the init in my Form, and the get_form_kwargs in my view:

Form

def __init__(self, *args, **kwargs):
    self.request = kwargs.pop('request')
    super(RecoverPasswordForm, self).__init__(*args, **kwargs)

def clean(self):
    ....
    self.request["user"] = User.objects.get(username__iexact=username, is_active=True)

View

def get_form_kwargs(self, **kwargs):
    kwargs = super(RecoverPassword, self).get_form_kwargs()
    kwargs["request"] = self.request
    return kwargs

Which leads to the following error

'WSGIRequest' object does not support item assignment

Can somebody give me an explanation of what I'm doing wrong, and push me in the right direction to solve this problem? Thanks in advance!


Solution

  • From what I understand, I think you are trying to send an email with reset password link to the user from your view after validating the username/email in your form. Next to add some info to the context, so it can be rendered in the template.

    So this can done by overriding the form_valid method in your class like:

    def form_valid(self, form):
        username = form.cleaned_data['username']
        email = form.cleaned_data['email']
        if username: user = User.objects.get(username__iexact=username, is_active=True)
        else: user = User.objects.get(email__iexact=email, is_active=True)
        send_email(user)
        data = {'info':'give your info here'}
        render(request, 'success.html', data)
    

    Learn more here

    Update:

    to can access the user object from the form do like:

    def clean():
        ...
        self.cleaned_data["user"] = User.objects.get(username__iexact=username, is_active=True)
    

    In your form_valid

    def form_valid(self, form):
        user = form.cleaned_data['user']
        send_email(user)
        data = {'info':'give your info here'}
        render(request, 'success.html', data)