13

我们实现了一个 LowerCaseCharField。我们很高兴听到更好的实施建议。

from django.db.models.fields import CharField

class LowerCaseCharField(CharField):
    """
    Defines a charfield which automatically converts all inputs to
    lowercase and saves.
    """

    def pre_save(self, model_instance, add):
        """
        Converts the string to lowercase before saving.
        """
        current_value = getattr(model_instance, self.attname)
        setattr(model_instance, self.attname, current_value.lower())
        return getattr(model_instance, self.attname)

其实我们喜欢拥有的是:

> modelinstance.field_name="TEST"
> print modelinstance.field_name
'test'

当前实现仅在保存时转换为小写。

4

4 回答 4

19

您可能希望覆盖to_python,这将允许您在进行数据库查找时比较非小写字符串。实际的方法是get_prep_value,但是因为它需要to_pythonCharField所以覆盖它更方便:

def to_python(self, value):
    value = super(LowerCaseCharField, self).to_python(value)
    if isinstance(value, basestring):
        return value.lower()
    return value

现在您可以执行以下查询:

MyModel.objects.filter(lccf="MiXeD")

编辑:

重新阅读您的问题,您似乎希望降低立即生效。为此,您需要创建一个描述符(具有__get____set__方法的新型 python 对象,请参阅相关模型的 python 文档和 django 代码)并在字段中覆盖contribute_to_class以将模型的字段设置为您的描述符。

这是我脑海中的一个完整示例,它应该可用于所有想要修改设置值的字段。

class ModifyingFieldDescriptor(object):
    """ Modifies a field when set using the field's (overriden) .to_python() method. """
    def __init__(self, field):  
        self.field = field  
    def __get__(self, instance, owner=None):
        if instance is None:
            raise AttributeError('Can only be accessed via an instance.')  
        return instance.__dict__[self.field.name]
    def __set__(self, instance, value):
        instance.__dict__[self.field.name] = self.field.to_python(value)

class LowerCaseCharField(CharField):
    def to_python(self, value):
        value = super(LowerCaseCharField, self).to_python(value)
        if isinstance(value, basestring):
            return value.lower()
        return value
    def contribute_to_class(self, cls, name):
        super(LowerCaseCharField, self).contribute_to_class(cls, name)
        setattr(cls, self.name, ModifyingFieldDescriptor(self))
于 2010-02-28T10:17:00.570 回答
2

另一种方法是在模型中添加一个pre_save钩子,然后使用 lower() 将所有要小写的字段转换为小写。此处以稍微不同的方式对此进行了讨论。这样,每次保存对象时,其字段都会转换为小写。

例子:

@receiver(pre_save, sender=YourModel)
def convert_to_lowercase(sender, instance, *args, **kwargs):
    instance.lowercase_field = instance.lowercase_field.lower()
于 2015-07-09T21:15:35.913 回答
1

使用 Python 属性并不简单,因为 django.models.Models 基于类属性神奇地设置了它们的实例属性。有一个开放的错误

我最终做了原始海报所做的事情。

这意味着你必须这样做:

>>> modelinstance.field_name="TEST"
>>> modelinstance.save() # Extra step
>>> print modelinstance.field_name
'test'
于 2010-03-01T13:28:41.523 回答
0

您尝试将 field_name 设为属性并在 getter 或 setter 中执行任何操作。

于 2010-02-28T10:16:13.540 回答