django - 从表单字段输入中清除额外空格的位置?

时间:2011-11-30 03:22:37

标签: django forms

我刚刚发现Django不会自动从表单字段输入中删除额外的空格,我想我理解其基本原理('框架不应该改变用户输入')。

我想我知道如何使用python的re:

删除多余的空格
#data = re.sub('\A\s+|\s+\Z', '', data)
data = data.strip()
data = re.sub('\s+', ' ', data)

问题是我应该在哪里这样做?据推测,这应该发生在一个形式的清洁阶段,但哪一个?理想情况下,我想清理所有额外空格的字段。如果它应该在clean_field()方法中完成,那就意味着我必须有很多基本上做同样事情的clean_field()方法,这似乎是很多重复。

如果不是表单的清理阶段,那么可能在表单基于的模型中?

感谢您的帮助!

W上。

8 个答案:

答案 0 :(得分:10)

我的方法是从here借来的。但是我使用mixin而不是继承django.forms.Form。这样我就可以同时使用FormModelForm。此处定义的方法会覆盖BaseForm的{​​{1}}方法。

_clean_fields

要使用,只需将mixin添加到表单

即可
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]

此外,如果要在保存没有表单的模型时修剪空白,可以使用以下mixin。默认情况下,不验证没有表单的模型。当我根据从外部rest api调用返回的json数据创建对象时,我使用它。

class MyForm(StripeWhitespaceMixin, ModelForm):
    ...

然后在你的models.py

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)

答案 1 :(得分:8)

创建自定义模型字段,以便自动使用自定义表单字段。

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)

然后在您的模型中,将django.db.models.CharField替换为TrimmedCharField

答案 2 :(得分:6)

如何将其添加到表单中的def clean(self):

有关进一步的文档,请参阅: https://docs.djangoproject.com/en/dev/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other

您的方法可能如下所示:

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

答案 3 :(得分:4)

使用以下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()

将此作为mixin添加到您的表单中,例如:

class MyForm(StripWhitespaceMixin, Form):
    pass

这类似于pymarco的答案,但不涉及复制粘贴,然后修改Django代码(_clean_fields方法的内容)。

相反,它会覆盖full_clean,但在对输入数据进行一些调整后会调用原始的full_clean方法。这使得它更少依赖于Django的Form类的实现细节,这些细节可能会发生变化(实际上自那个答案以来已经发生了变化)。

答案 4 :(得分:0)

在这种情况下,创建自己的表单字段可能很有用(听起来并不那么难)。在clean()方法中,您将删除多余的空格。

引用文档:

  

您可以轻松创建自定义Field类。要做到这一点,只需创建一个   django.forms.Field的子类。它的唯一要求就是它   实现一个clean()方法,并且它的__init __()方法接受   核心参数(必需,标签,初始,小部件,   help_text)。

有关它的更多信息:https://docs.djangoproject.com/en/1.3/ref/forms/fields/#creating-custom-fields

答案 5 :(得分:0)

执行此操作的一种方法是指定用于删除空格的自定义表单窗口小部件:

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

然后在ModelForm中使用它:

class MyForm(ModelForm):
    strip_field = StripTextField()

    class Meta:
        model = MyModel

但是,最好的地方是在您的视图 之后验证表单;如果您使用ModelForm s。

,则在对数据库进行任何插入或其他数据操作之前

您始终可以创建自己的非ModelForm表单,并控制字段的各个方面并以此方式进行验证。

ModelForm的验证添加了对违反db约束的值的检查;因此,如果该字段可以接受' hello '作为有效输入,则ModelForm的is_valid()没有理由去除空白(因为除了你提到的“框架之外,它不会产生任意清理逻辑)不应该改变用户的输入“)。

答案 6 :(得分:0)

如果要剥离()项目中的每个CharField; monkeypatch CharField的默认清洁方法可能最简单。

内:monkey_patch/__init__.py

from django.forms.fields import CharField

def new_clean(self, value):
    """ Strip leading and trailing whitespace on all CharField's """
    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

答案 7 :(得分:0)

自Django 1.9起,您可以在表单定义的字段中使用strip关键字参数:

  

条¶       Django 1.9中的新功能。

If True (default), the value will be stripped of leading and trailing whitespace.

应该给出类似的内容:

class MyForm(forms.Form):

    myfield = forms.CharField(min_length=42, strip=True)

并且由于其默认值为True ,因此它应与django>=1.9自动使用。

RegexField也有关。