I’ve had the case, multiple times these last month were I wanted to validate only some form fields and then modify the form before validating the rest of the form. I had some very complex situations but the simplest one is were some fields are required only if the user ticks a checkbox.
Now I know I can leave these fields as not required then verify the data myself in BaseForm.clean
but this is just code repetition since requirement check is already done in BaseForm._clean_fields
.
What I propose is to modify BaseForm._clean_fields
like this:
def _clean_fields(self, fields=None):
fields = fields or self._bound_items()
for name, bf in fields:
field = bf.field
value = bf.initial if field.disabled else bf.data
try:
if isinstance(field, FileField):
value = field.clean(value, bf.initial)
else:
value = field.clean(value)
self.cleaned_data[name] = value
if hasattr(self, "clean_%s" % name):
value = getattr(self, "clean_%s" % name)()
self.cleaned_data[name] = value
except ValidationError as e:
self.add_error(name, e)
so that I can validate my form like this:
def _clean_fields(self, fields=None):
super()._clean_fields(fields=(...))
# Change fields requirements or autocomplete form data
# with DB data
super()._clean_fields(fields=(...)) # clean rest of the fields.
Even better: _clean_fields
could be part of the public API:
class BaseForm(RenderableFormMixin):
def clean_field(self, name):
bf = self[name]
field = bf.field
value = bf.initial if field.disabled else bf.data
try:
if isinstance(field, FileField):
value = field.clean(value, bf.initial)
else:
value = field.clean(value)
self.cleaned_data[name] = value
if hasattr(self, "clean_%s" % name):
value = getattr(self, "clean_%s" % name)()
self.cleaned_data[name] = value
except ValidationError as e:
self.add_error(name, e)
def clean_fields(self):
for name in self.fields:
self.clean_field(name)
def _clean_fields(self):
self.clean_fields()
Here _clean_fields
is kept for retro-compatibility.