Where to clear extra spaces from form field input?

I just discovered that Django does not automatically extract extra spaces from the input of a form field, and I think I understand the rationale ("framework should not change user input").

I think I know how to remove extra spaces with python re:

#data = re.sub('\A\s+|\s+\Z', '', data) data = data.strip() data = re.sub('\s+', ' ', data) 

The question is where should I do this? Presumably this should happen in one form of pure stages, but which one? Ideally, I would like to clear all fields of extra spaces. If you need to do this in the clean_field () method, it would mean that I should have many clean_field () methods that basically do the same thing, which seems like a lot of repetition.

If not the stage of cleaning the mold, then perhaps in the model on which the mold is based on?

Thank you for your help!

Sh.

+7
source share
7 answers

My approach is borrowed from here . But instead of subclassing django.forms.Form, I use mixin. That way I can use it with both Form and ModelForm . The method defined here overrides the BaseForm _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, just add mixin to your form

 class MyForm(StripeWhitespaceMixin, ModelForm): ... 

Alternatively, if you want to trim whitespace while saving models that don't have a form, you can use the following mixin. By default, models without forms are not checked. I use this when I create objects based on json data returned from an external api rest 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 file

 class MyModel(ValidateModelMixin, Model): .... 
+10
source

Create a custom model field so that your custom form field is used automatically.

 class TrimmedCharFormField(forms.CharField): def clean(self, value): if value: value = value.strip() return super(TrimmedCharFormField, self).clean(value) # (If you use South) add_introspection_rules([], ["^common\.fields\.TrimmedCharField"]) class TrimmedCharField(models.CharField): __metaclass__ = models.SubfieldBase def formfield(self, **kwargs): return super(TrimmedCharField, self).formfield(form_class=TrimmedCharFormField, **kwargs) 

Then in your models just replace django.db.models.CharField with TrimmedCharField

+8
source

How to add this to def clean(self): in a form?

Additional documentation: https://docs.djangoproject.com/en/dev/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other

Your method might look something like this:

 def clean(self): cleaned_data = self.cleaned_data for k in self.cleaned_data: data = re.sub('\A\s+', '', self.cleaned_data[k]) data = re.sub('\s+\Z', '', data) data = re.sub('\s+', ' ', data) cleaned_data[k]=data return cleaned_data 
+6
source

Use the following mixin:

 class StripWhitespaceMixin(object): def full_clean(self): # self.data can be dict (usually empty) or QueryDict here. self.data = self.data.copy() is_querydict = hasattr(self.data, 'setlist') strip = lambda val: val.strip() for k in list(self.data.keys()): if is_querydict: self.data.setlist(k, map(strip, self.data.getlist(k))) else: self.data[k] = strip(self.data[k]) super(StripWhitespaceMixin, self).full_clean() 

Add this as mixin to your form, for example:

 class MyForm(StripWhitespaceMixin, Form): pass 

This is similar to pymarco's answer, but does not include copying and then modifying the Django code (contents of the _clean_fields method).

Instead, it overrides full_clean , but calls the original full_clean method after making some changes to the input. This makes it less dependent on the details of the implementation of the Django Form class, which may change (and actually have changed since the answer).

+4
source

In this case, it would be useful to create your own form field (this is not as difficult as it seems). In the clean() method, you must remove the extra spaces.

Indication of documentation:

You can easily create custom field classes. To do this, simply subclass django.forms.Field. His only requirements are that he implement the clean () method and that his __init __ () method accepts the main arguments (required, shortcut, initial, widget, help_text).

More on this: https://docs.djangoproject.com/en/1.3/ref/forms/fields/#creating-custom-fields

0
source

One way to do this is to specify a custom form widget that separates spaces:

 >>> from django import forms >>> class StripTextField(forms.CharField): ... def clean(self,value): ... return value.strip() ... >>> f = StripTextField() >>> f.clean(' hello ') 'hello' 

Then, to use this in your ModelForm:

 class MyForm(ModelForm): strip_field = StripTextField() class Meta: model = MyModel 

However, the best place for this in your presentation is after , the form has been verified; before making any insertions in db or other data manipulations if you are using ModelForm s.

You can always create your own ModelForm forms and control every aspect of the field and validation in this way.

ModelForm validation adds value checks that violate db limits; therefore, if a field can accept ' hello ' as a valid input, ModelForm is_valid() will not make sense to strip spaces (since this will not do for arbitrary pure logic, in addition to what you mentioned, "user input should not be changed ").

0
source

If you want to share () each CharField in your project; it might be easier monkeypatch CharField default cleaning method.

inside: monkey_patch/__init__.py

 from django.forms.fields import CharField def new_clean(self, value): """ Strip leading and trailing whitespace on all CharField """ if value: # We try/catch here, because other fields subclass CharField. So I'm not totally certain that value will always be stripable. try: value = value.strip() except: pass return super(CharField, self).clean(value) CharField.clean = new_clean 
0
source

All Articles