(Django) обрезать пробелы из charField

Как очистить пробелы (обрезать) от конца charField в Django?

вот моя модель, как вы можете видеть, я пытался положить чистые методы, но они никогда не запускаются.

Я также пробовал делать 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()

Edited: обновлен код до моей последней версии. Я не уверен, что делаю. неправильно, поскольку он все еще не удаляет пробелы (обрезка) поля имени.

6 ответов


очистка модели должна быть вызвана (это не автоматически), поэтому поместите некоторые self.full_clean() в вашем сохранить method.
http://docs.djangoproject.com/en/dev/ref/models/instances/#django.db.models.Model.full_clean

что касается вашей формы, вам нужно вернуть очищенные данные.

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

как-то я думаю, что вы просто пытались сделать кучу вещей, которые не работают. Помните, что формы и модели 2 очень разные вещи.

проверить документы форм о проверке форм 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()

при использовании экземпляра 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()

Я нахожу следующий фрагмент кода полезным - он обрезает пробелы для всех полей модели, которые подкласс либо 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())

Если у вас так много полей данных, которые нужно обрезать, почему бы не попробовать расширить 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)):

я обрабатываю это в представлениях как декоратор. Я также усекаю значения полей, которые превышают значение 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 1.9 предлагает простой способ выполнения этого. Используя strip аргумент, значение по умолчанию которого True, вы можете убедиться, что ведущие и конечные пробелы обрезаны. Вы можете сделать это только в полях формы, хотя для того, чтобы убедиться, что пользовательский ввод обрезается. Но это все равно не защитит саму модель. Если вы все еще хотите это сделать, вы можете использовать любой из методов выше.

для получения дополнительной информации, посетите https://docs.djangoproject.com/en/1.9/ref/forms/fields/#charfield


Если вы все еще не на 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()