Django LowerCaseCharField

Ние внедрихме 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'

текущата реализация преобразува само в малки букви, когато бъде запазена.


person Can Burak Çilingir    schedule 28.02.2010    source източник
comment
Вижте @mcastle решение stackoverflow.com/a/24495517/2034015   -  person zurfyx    schedule 25.03.2016


Отговори (4)


Може да искате да замените to_python, което ще ви позволи да сравнявате низове, които не са с малки букви, когато правите справки в база данни. Действителният метод е get_prep_value, но тъй като той извиква to_python за CharField, по-удобно е да замените това:

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

Редактиране:

Препрочитайки въпроса ви, изглежда, че искате намаляването да влезе в сила незабавно. За да направите това, ще трябва да създадете дескриптор (нов стил Python обект с __get__ и __set__ методи, вижте документите на 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))
person Will Hardy    schedule 28.02.2010
comment
Необходимостта от това се появи, когато съхраняваме имейл адреси, така че всъщност to_python сам по себе си би бил достатъчен, за да реши проблема ни. Сега дискусията е за нормализиране на данните в базата данни чрез преобразуването им в малки букви е логично или не. RFC, цитиран на en.wikipedia.org/wiki/E-mail_address#RFC_specification казва, че не се препоръчва да се прави разлика между главни и малки имейл адреси. Пътят, който бих искал да поема, е, 1. Нормализирайте го, като го преобразувате в малки букви 2. Игнорирайте регистъра, докато правите заявки, тъй като въвеждането на потребителя ще бъде без значение. - person Can Burak Çilingir; 28.02.2010
comment
Горният код трябва да прави и двете: 1. низът се нормализира в момента, в който атрибутът е зададен (ModifyingFieldDescriptor) 2. всички низове, използвани в заявките, се нормализират, така че по подразбиране са без значение от главни и малки букви (to_python). Нормализирането е добър подход, защото никога няма да имате нужда от оригиналната, чувствителна към малки и главни букви стойност и ще ви позволи да имате уникални проверки, управлявани от база данни и т.н. - person Will Hardy; 28.02.2010
comment
Вашият подход изглежда е правилният начин да направите това. Това е първият път, когато трябва да използваме doprinos_to_class, така че това е ново приключение. Благодаря за отделеното време и всъщност също за промоцията на stackoverflow към мен. - person Can Burak Çilingir; 28.02.2010

Друг начин да го направите е да добавите pre_save закачете се към вашия модел и след това просто преобразувайте всички полета, които искате да бъдат с малки букви, в малки букви там с помощта на lower(). Това се обсъжда тук по малко по-различен начин. По този начин всеки път, когато обектът бъде запазен, неговото поле се преобразува в малки букви.

Пример:

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

Използването на свойства на Python не е лесно поради начина, по който django.models.Models магически задават своите атрибути на екземпляр въз основа на атрибути на клас. Има открит бъг за това.

В крайна сметка направих точно това, което направи оригиналният плакат.

Това означава, че трябва да направите:

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

Опитвате се да направите field_name свойство и правите каквото и да е в getter или setter.

person Kugel    schedule 28.02.2010
comment
+1: Това не е различен тип поле, това е ограничение на съществуващ тип. - person S.Lott; 28.02.2010
comment
Въпросът е, че имаме това ограничение на 12 полета на 11 различни модела, така че това е решението, което открихме, че се подчинява на DRY. - person Can Burak Çilingir; 28.02.2010