Django LowerCaseCharField

后端 未结 4 970
我在风中等你
我在风中等你 2021-02-13 17:22

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

from django.db.models.fields import CharField

class LowerCaseC         


        
相关标签:
4条回答
  • 2021-02-13 17:45

    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))
    
    0 讨论(0)
  • 2021-02-13 17:50

    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()
    
    0 讨论(0)
  • 2021-02-13 17:58

    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'
    
    0 讨论(0)
  • 2021-02-13 17:58

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

    0 讨论(0)
提交回复
热议问题