Django LowerCaseCharField

发布于 2024-08-23 14:48:26 字数 727 浏览 5 评论 0原文

我们实现了一个 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'

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

We implemented a LowerCaseCharField. We would be happy to hear better implementation suggestions.

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)

In fact we love to have is:

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

current implementation only converts to lowercase when it is saved.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

吃素的狼 2024-08-30 14:48:26

您可能希望覆盖to_python,这将允许您在进行数据库查找时比较非小写字符串。实际的方法是 get_prep_value,但由于它为 CharField 调用 to_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")

< em>编辑:

重读您的问题,您似乎希望降低立即生效。为此,您需要创建一个描述符(带有 __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))

You may wish to override to_python, which will allow you to compare non-lowercase strings when doing database lookups. The actual method is get_prep_value, but as that calls to_python for CharField, it's more convenient to override that:

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

Now you can do queries like:

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

Edit:

Rereading your question, it looks like you want the lowering to take effect immediately. To do this, you'll need to create a descriptor (a new-style python object with __get__ and __set__ methods, see the python docs and the django code for related models) and override contribute_to_class in the field to set the model's field to your descriptor.

Here is a full example off the top of my head, which should be reusable for all fields that want to modify the value on setting.

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))
叹倦 2024-08-30 14:48:26

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

示例:

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

Another way to do it would be to add a pre_save hook to your model, and then just convert all the fields you want to be lowercase to lowercase there using lower(). This is discussed here in a slightly different fashion. This way, any time the object is saved its field is converted to lower case.

Example:

@receiver(pre_save, sender=YourModel)
def convert_to_lowercase(sender, instance, *args, **kwargs):
    instance.lowercase_field = instance.lowercase_field.lower()
呆橘 2024-08-30 14:48:26

使用 Python 属性并不简单,因为 django.models.Models 基于类属性神奇地设置其实例属性。为此有一个未解决的错误

我最终完全按照原来的海报做了。

这意味着你必须这样做:

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

Using Python properties is not straightforward because of the way django.models.Models magically set their instance attributes based on class attributes. There is an open bug out for this.

I ended up doing exactly what the original poster did.

It means you have to do:

>>> modelinstance.field_name="TEST"
>>> modelinstance.save() # Extra step
>>> print modelinstance.field_name
'test'
饭团 2024-08-30 14:48:26

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

You try making field_name a property and do whatever in getter or setter.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文