My approach is borrowed from here. But instead of subclassing django.forms.Form, I use a mixin. That way I can use it with both Form
and ModelForm
. The method defined here overrides BaseForm
's _clean_fields
method.
class StripWhitespaceMixin(object):
def _clean_fields(self):
for name, field in self.fields.items():
# value_from_datadict() gets the data from the data dictionaries.
# Each widget type knows how to retrieve its own data, because some
# widgets split data over several HTML fields.
value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
try:
if isinstance(field, FileField):
initial = self.initial.get(name, field.initial)
value = field.clean(value, initial)
else:
if isinstance(value, basestring):
value = field.clean(value.strip())
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._errors[name] = self.error_class(e.messages)
if name in self.cleaned_data:
del self.cleaned_data[name]
To use, simply add the mixin to your form
class MyForm(StripeWhitespaceMixin, ModelForm):
...
Also, if you want to trim whitespace when saving models that do not have a form you can use the following mixin. Models without forms aren't validated by default. I use this when I create objects based off of json data returned from external rest api call.
class ValidateModelMixin(object):
def clean(self):
for field in self._meta.fields:
value = getattr(self, field.name)
if value:
# ducktyping attempt to strip whitespace
try:
setattr(self, field.name, value.strip())
except Exception:
pass
def save(self, *args, **kwargs):
self.full_clean()
super(ValidateModelMixin, self).save(*args, **kwargs)
Then in your models.py
class MyModel(ValidateModelMixin, Model):
....