Clear all Form Fields on Validation Error in Djang

2019-09-14 18:20发布

问题:

I have a simple user registration form (in forms.py):

from django.contrib.auth.models import User

class UserForm(forms.ModelForm):
    password = forms.CharField(widget=forms.PasswordInput
                               validators=[MinLengthValidator(6)])
    password_repeat = forms.CharField(widget=forms.PasswordInput)

    class Meta:
        model = User
        fields = ['username', 'password','password_repeat']

If someone tries to enter something and the validation fails I want the same form to be rendered again but all fields should be cleared. At the moment my view looks like this (in views.py):

def signup(request):
    form = UserForm(request.POST or None)

    if form.is_valid():
        user = form.save(commit=False)
        username = form.cleaned_data['username']
        password = form.cleaned_data['password']
        password_repeat = form.cleaned_data['password-repeat']
        user.set_password(password)
        user.save()
        user = auth.authenticate(username=username, password=password)
        if user is not None and user.is_active:
            auth.login(request, user)
            return redirect('/')

return render(request, 'signup.html', {'form': form})

The problem is that the form.fields['username'] field still contains the username that was entered and is thus passed to render.

I've been searching for a solution a while now but can't find it. My guess is that the solution has something to do with the clean() method that I don't seem to get.

回答1:

This is an odd thing to want to do - it is the opposite of the question people normally ask, as most people want to preserve the fields and show the errors.

However, if you really want to clear the form, you should just instantiate a new one.

if form.is_valid():
    ...
else:
    form = UserForm()
return render(request, 'signup.html', {'form': form})


回答2:

To always clear a particular form field while preserving all form validation errors, you can create a custom input widget that always "forgets" it's old value. For example:

from django import forms

class NonstickyTextInput(forms.TextInput):
    '''Custom text input widget that's "non-sticky"
    (i.e. does not remember submitted values).
    '''
    def get_context(self, name, value, attrs):
        value = None  # Clear the submitted value.
        return super().get_context(name, value, attrs)

class MyForm(forms.Form):
    username = forms.CharField(widget=NonstickyTextInput())
    # ...

Reference: django.forms.Widget.get_context

Behavior

Suppose we are using MyForm in such a view:

from django.shortcuts import render, redirect
from myapp.forms import MyForm

def myview(request):
    if request.method == 'POST':
        form = MyForm(request.POST)
        if form.is_valid():
            # Do something with the submitted values...
            return redirect('home_page')
    else:
        form = MyForm()
    return render(request, 'myapp/myview.html', {'form': form})

When the form encounters any validation error and the form is re-displayed, all the usual validation error messages will be shown on the form, but the displayed username form field will be blank.