(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()

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

Ответ 1

Очистка модели должна быть вызвана (она не автоматическая), поэтому поместите некоторый 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()

Ответ 2

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

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())

Ответ 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))

UPDATE: Для версий Django <= 1.7, если вы хотите расширить поле, вы должны использовать metaslass models.SubfieldBase. Итак, вот это будет:

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

Ответ 4

Я обрабатываю это в виде декоратора. Я также усекаю значения полей, которые превышают значение max_length CharField.

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 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

Ответ 5

Django 1.9 предлагает простой способ выполнить это. Используя аргумент strip, значение по умолчанию которого равно True, вы можете убедиться, что верхний и конечный пробелы обрезаны. Это можно сделать только в полях формы, чтобы убедиться, что пользовательский ввод обрезается. Но это все равно не защитит сама модель. Если вы все еще хотите это сделать, вы можете использовать любой из вышеперечисленных методов.

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

Ответ 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()