【问题标题】:(Django) Trim whitespaces from charField(Django) 从 charField 中修剪空格
【发布时间】:2011-02-18 15:19:04
【问题描述】:

如何在 Django 中去除 charField 末尾的空格(修剪)?

这是我的模型,如您所见,我尝试使用干净的方法,但这些方法永远不会运行。

我也尝试过name.strip()models.charField().strip(),但这些也不起作用。

有没有办法强制 charField 为我自动修剪?

谢谢。

from django.db import models
from django.forms import ModelForm
from django.core.exceptions import ValidationError
import datetime

class Employee(models.Model):
    """(Workers, Staff, etc)"""
    name                = models.CharField(blank=True, null=True, max_length=100)

    def save(self, *args, **kwargs):
        try:
            # This line doesn't do anything??
            #self.full_clean()
            Employee.clean(self)
        except ValidationError, e:
            print e.message_dict

        super(Employee, self).save(*args, **kwargs) # Real save

    # If I uncomment this, I get an TypeError: unsubscriptable object
    #def clean(self):
    #   return self.clean['name'].strip()

    def __unicode__(self):
        return self.name

    class Meta:
        verbose_name_plural = 'Employees'

    class Admin:pass


class EmployeeForm(ModelForm):
    class Meta:
        model = Employee

    # I have no idea if this method is being called or not  
    def full_clean(self):       
        return super(Employee), self.clean().strip()
        #return self.clean['name'].strip()

已编辑:将代码更新到我的最新版本。我不确定我做错了什么,因为它仍然没有去除空格(修剪)名称字段。

【问题讨论】:

    标签: python django django-models removing-whitespace


    【解决方案1】:

    当您使用 ModelForm 实例创建/编辑模型时,保证会调用模型的 clean() 方法。因此,如果您想从字段中去除空格,只需向模型添加一个 clean() 方法(无需编辑 ModelForm 类):

    class Employee(models.Model):
        """(Workers, Staff, etc)"""
        name = models.CharField(blank=True, null=True, max_length=100)
    
        def clean(self):
            if self.name:
                self.name = self.name.strip()
    

    我发现以下代码 sn-p 很有用 - 它为模型的所有字段修剪空白,这些字段是 CharField 或 TextField 的子类(因此这也捕获了 URLField 字段),而无需单独指定字段:

    def clean(self):
        for field in self._meta.fields:
            if isinstance(field, (models.CharField, models.TextField)):
                value = getattr(self, field.name)
                if value:
                    setattr(self, field.name, value.strip())
    

    有人正确地指出,您不应该在名称声明中使用 null=True。最佳做法是避免 null=True 用于字符串字段,在这种情况下,上述简化为:

    def clean(self):
        for field in self._meta.fields:
            if isinstance(field, (models.CharField, models.TextField)):
                setattr(self, field.name, getattr(self, field.name).strip())
    

    【讨论】:

    • 很好的解决方案。但是,我要更改的一件事是:if value and hasattr(value, 'strip'): 因为某些自定义字段不包含值的 strip 方法(至少是我的情况) .这可以防止这种情况发生。
    【解决方案2】:

    模型清理必须被调用(它不是自动的)所以在你的保存方法中放置一些self.full_clean()
    http://docs.djangoproject.com/en/dev/ref/models/instances/#django.db.models.Model.full_clean

    对于你的表单,你需要返回剥离后的清理数据。

    return self.cleaned_data['name'].strip()
    

    不知何故,我认为你只是试图做一堆不起作用的东西。请记住,表单和模型是两种截然不同的东西。

    查看表单文档以了解如何验证表单 http://docs.djangoproject.com/en/dev/ref/forms/validation/

    super(Employee), self.clean().strip() makes no sense at all!

    这是你的代码修复:

    class Employee(models.Model):
        """(Workers, Staff, etc)"""
        name = models.CharField(blank=True, null=True, max_length=100)
    
        def save(self, *args, **kwargs):
            self.full_clean() # performs regular validation then clean()
            super(Employee, self).save(*args, **kwargs)
    
    
        def clean(self):
            """
            Custom validation (read docs)
            PS: why do you have null=True on charfield? 
            we could avoid the check for name
            """
            if self.name: 
                self.name = self.name.strip()
    
    
    class EmployeeForm(ModelForm):
        class Meta:
            model = Employee
    
    
        def clean_name(self):
            """
            If somebody enters into this form ' hello ', 
            the extra whitespace will be stripped.
            """
            return self.cleaned_data.get('name', '').strip()
    

    【讨论】:

    • 我仍然有问题 - 它仍然没有去除空白(修剪)。我尝试按照您发布的教程以及您在保存方法中调用 full_clean() 的想法进行操作。我很难理解 a) EmployeeForm 是否被调用? b) 是否调用了 full_clean() 方法?我在我的问题中更新了我的代码示例。我希望我能找到正确的方向。
    • 感谢您的帮助,我对 Django/Python 还是很陌生;对于我应该如何实现各种功能的各种错误和误解,我们深表歉意。
    • 没问题。只需查阅文档而不是猜测,您就会明白! Django 文档在清晰和示例方面非常出色。
    • 效果很好。关于您对名称字段为何接受 null=True 的评论,这是因为我刚开始使用 Django,对所有内容都不太熟悉。无论如何,谢谢,因为这解决了我的问题。希望我现在可以在未来将其推广到所有文本字段。
    • null=True 表示数据库可以存储null 值,这对于可选的Integer 字段等字段很重要,因为'' 将无效。对于字符字段,'' 通常可以完全接受为空白值,这也确保该字段始终返回一个字符串,因此您可以安全地对其进行任何 python 字符串操作,如strip()
    【解决方案3】:

    如果您有这么多数据字段需要修剪,为什么不尝试扩展 CharField?

    from django.db import models
    from django.utils.translation import ugettext_lazy as _
    
    class TrimCharField(models.CharField):
       description = _(
           "CharField that ignores leading" 
           " and trailing spaces in data")
    
       def get_prep_value(self, value)
           return trim(super(TrimCharField, self
               ).get_prep_value(value))
    
       def pre_save(self, model_instance, add):
           return trim(super(TrimCharField, self
               ).pre_save(model_instance, add))
    

    更新: 对于 Django 版本

    class TrimCharField(six.with_metaclass(
        models.SubfieldBase, models.CharField)):
    

    【讨论】:

      【解决方案4】:

      Django 1.9 提供了一种简单的方法来实现这一点。通过使用默认为 True 的 strip 参数,您可以确保修剪前导和尾随空格。您只能在表单字段中执行此操作,以确保修剪用户输入。但这仍然不能保护模型本身。如果您仍然想这样做,您可以使用上述任何一种方法。

      欲了解更多信息,请访问https://docs.djangoproject.com/en/1.9/ref/forms/fields/#charfield

      【讨论】:

      • 我需要加倍关注这个评论,以防将来偶然发现这个问题的人:在 Django 1.9 之后,即使你使用 ModelForm,下面的 charField 也会有 strip 到 @默认为 987654328@。这意味着您不需要手动设置任何内容。但是,请注意,根据您实现视图的方式,您可能仍会看到未修剪的字段,因为在 form 对象上您返回到视图时,它仍然未修剪。
      • 1.9以后默认开启strip。如果要禁用此功能,请查看我的回答:stackoverflow.com/a/68112671/2251785
      【解决方案5】:

      我作为装饰者在视图中处理这个问题。我还截断了超过 CharField max_length 值的字段值。

      from django import forms
      from django import models
      from django.db.models.fields import FieldDoesNotExist
      from django.utils.encoding import smart_str
      
      class CleanCharField(forms.CharField):
              """Django's default form handling drives me nuts wrt trailing
              spaces.  http://code.djangoproject.com/attachment/ticket/6362
              """
              def clean(self, value):
                  if value is None:
                      value = u''
                  value = smart_str(value).strip()
                  value = super(forms.CharField, self).clean(value)
                  return value
      
      def truncate_charfield(model):
          """decorator to truncate CharField data to model field max_length.
          Apply to the clean method in views Form:
      
          @truncate_charfield(MyModel)
          def clean(self):
              ...
          """
          def wrap(f):
              def wrapped_f(*args):
                  f(*args)
                  d = args[0].cleaned_data
                  for field in model._meta.fields:
                      try:
                          mf = model._meta.get_field(field.name)
                          if isinstance(mf, models.CharField) and field.name in d:
                              d[field.name] = d[field.name][:mf.max_length]
                      except FieldDoesNotExist:
                          pass
                  return d
              return wrapped_f
          return wrap
      

      【讨论】:

      • 谢谢,但对我来说似乎有点太高级了——我不知道我会把这个文件放在哪里,我会怎么称呼它,等等;但是当我开始学习 Django/Python 时,我相信我会一路学习。再次感谢。
      • zardon,你可以简单地把它放在一个模块中,比如 maxtruncate.py 然后导入你的views.py: from maxtruncate import CleanCharField, truncate_charfield。然后用 CleanCharField 替换 CharField 并将 truncate_charfield 装饰器放在你的 clean 方法的顶部。主要优点是您的输入字段不会超过您的 max_length ...这将导致您的数据库出现令人讨厌的运行时错误。
      【解决方案6】:

      如果您还没有使用 Django 1.9+,请为您(和我)感到羞耻,请将其放入您的表单中。这类似于@jeremy-lewis 的回答,但我对他的回答有几个问题。

      def clean_text_fields(self):
          # TODO: Django 1.9, use on the model strip=True
          # https://docs.djangoproject.com/en/1.9/ref/forms/fields/#charfield
          from django.forms.fields import CharField
          cd = self.cleaned_data
          for field_name, field in self.fields.items():
              if isinstance(field, CharField):
                  cd[field_name] = cd[field_name].strip()
                  if self.fields[field_name].required and not cd[field_name]:
                      self.add_error(field_name, "This is a required field.")
      
      def clean(self):
          self.clean_text_fields()
      

      【讨论】:

        猜你喜欢
        • 2012-03-14
        • 1970-01-01
        • 2010-12-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-23
        相关资源
        最近更新 更多