问题
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.
回答1:
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))
回答2:
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'
回答3:
You try making field_name a property and do whatever in getter or setter.
回答4:
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()
来源:https://stackoverflow.com/questions/2350681/django-lowercasecharfield