Python Django小写字母charfield

Python Django小写字母charfield,python,django,lowercase,Python,Django,Lowercase,我们实现了一个小写的charfield。我们很高兴听到更好的实施建议 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,

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

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'

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

您尝试将字段命名为a,并在getter或setter中执行任何操作。

您可能希望将
重写为python
,这将允许您在执行数据库查找时比较非小写字符串。实际的方法是
get\u prep\u value
,但是当它为
CharField
调用
到\u python
时,更方便地覆盖它:

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")
编辑:

重读你的问题,看起来你希望降价立即生效。为此,您需要创建一个描述符(一个带有
\uuuu get\uuuuu
\uuuu set\uuuu
方法的新型python对象,请参见和相关模型的django代码),并覆盖字段中的
贡献给类
,以将模型的字段设置为描述符

下面是一个完整的示例,对于所有想要修改设置上的值的字段,它都应该是可重用的

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

使用Python属性并不简单,因为django.models.models会根据类属性神奇地设置它们的实例属性。这是一个值得考虑的问题

我最终做的和原来的海报一模一样

这意味着你必须做:

>>> modelinstance.field_name="TEST"
>>> modelinstance.save() # Extra step
>>> print modelinstance.field_name
'test'

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

示例:

@receiver(pre_save, sender=YourModel)
def convert_to_lowercase(sender, instance, *args, **kwargs):
    instance.lowercase_field = instance.lowercase_field.lower()

当我们存储电子邮件地址时,这种需求就浮出水面,因此事实上,使用python本身就足以解决我们的问题。现在,讨论的是如何通过将数据库中的数据转换为小写字母来规范化数据是否符合逻辑。上引用的rfc表示,不鼓励区分大小写电子邮件地址。我想走的道路是,1。通过将其转换为小写2来规范化。在查询时忽略大小写,因为用户输入将不区分大小写。上面的代码应同时执行以下两个操作:1。设置属性时,字符串即被标准化(
ModifyingFieldDescriptor
)2。查询中使用的所有字符串都是标准化的,因此默认情况下它们不区分大小写(
to_python
)。规范化是一种很好的方法,因为您永远不需要原始的、区分大小写的值,它将使您能够进行数据库驱动的唯一检查等。您的方法似乎是正确的。这是我们第一次需要使用contribute_to_类,所以这是一次新的冒险。感谢您的时间,事实上也向我推广stackoverflow。+1:这不是一种不同类型的字段,而是对现有类型的约束。重点是我们对11种不同模型上的12个字段有此约束,因此这是我们发现的遵循“DRY”的解决方案。请参阅@mcastle solution