Пользовательское поле модели Django с проверкой ... как подключить его к ModelForm - PullRequest
0 голосов
/ 18 декабря 2009

Обычное явление, которое у меня возникает с одним конкретным проектом, заключается в том, что он требует от пользователя ввода размеров (для ширины / глубины / высоты) в футах и ​​дюймах. Для этого измерения необходимо выполнить вычисления, поэтому я работал над пользовательским типом поля, который принимает измерение в футах / дюймах (например, 1'-10 ") и сохраняет его в базе данных как десятичное число, используя регулярное выражение для анализа ввода. Поле всегда отображается для конечного пользователя в футах-дюймах (с возможной целью написания метод для возможности отображения в метрике и взаимодействия с measure.py и geodjango). То, что я имею до сих пор, определенно не СУХО, но кроме этого, у меня проблемы с проверкой на уровне формы. Само поле пользовательской модели работает правильно (из того, что я видел), и я написал метод очистки поля формы, который должен работать для проверки поля. Мой вопрос заключается в том, как подключить это поле формы обратно к форме моей модели для работы со всеми полями ширины / глубины / высоты. Я думаю, что, возможно, переопределить init для формы модели (a la self.fields ['deep'] ...), но я не совсем уверен, куда идти дальше ...

DCML_PATTERN = re.compile(r'^(?P<feet>\d+)(?P<dec_inch>\.?\d*)\'?$')
FTIN_PATTERN = re.compile(r'^(?P<feet>\d+)\'?\s*-?\s*(?P<inch>[0-9]|10|11)?\"?$')

class FtInField(models.Field):
        __metaclass__ = models.SubfieldBase

        empty_strings_allowed = False

        def db_type(self):
                return 'double'

        def get_internal_type(self):
                return "FtInField"

        def to_python(self,value):
                if value is u'' or value is None:
                        return None
                if isinstance(value, float):
                        m = FTDCML_PATTERN.match(str(value))
                        if m is None:
                                raise Exception('Must be an integer or decimal number')
                        feet = int(m.group('feet'))
                        dec_inch = float(m.group('dec_inch') or 0)
                        inch = dec_inch * 12
                        return "%d\'-%.0f\"" % (feet,inch)
                return value

        def get_db_prep_value(self,value):
                if value is u'' or value is None:
                        return None
                m = FTIN_PATTERN.match(value)
                if m is None:
                        raise Exception('Must be in X\'-Y" Format')
                feet = int(m.group('feet'))
                inch = int(m.group('inch') or 0)
                return (feet + (inch/float(12)))

class FtInField(forms.Field):
        def clean(self,value):
                super(FtInField, self).clean(value)
                if value is u'' or value is None:
                        raise forms.ValidationError('Enter a dimension in X\'-Y" format')
                m = FTIN_PATTERN.match(value)
                if m is None:
                        raise forms.ValidationError('Must be in X\'-Y" Format')
                feet = int(m.group('feet'))
                inch = int(m.group('inch') or 0)
                value = '%d\'-%.0f"' % (feet,inch)
                return value

class ProductClass(models.Model):
        productname = models.CharField('Product Name', max_length=60,blank=True)
        depth = FtInField('Depth (Feet/Inches)')
        width = FtInField('Width (Feet/Inches)')
        height = FtInField('Height (Feet/Inches)')

class ProductClassForm(forms.ModelForm):
        depth = FtInField()
        width = FtInField()
        height = FtInField()

        class Meta:
                model = ProductClass

class ProductClassAdmin(admin.ModelAdmin):
        form = ProductClassForm

Ответы [ 2 ]

2 голосов
/ 19 декабря 2009

Спасибо, спасибо вам обоим. Это то, что я придумал (основываясь на обоих ваших советах). Я буду работать над определением типа данных, чтобы сделать его лучше с точки зрения повторения, но пока что это работает ... (Я был так близко, но так далеко ...) Вы, ребята, удивительны. Спасибо.

DCML_PATTERN = re.compile(r'^(?P<feet>\d+)(?P<dec_inch>\.?\d*)\'?$')
FTIN_PATTERN = re.compile(r'^(?P<feet>\d+)\'?\s*-?\s*(?P<inch>[0-9]|10|11)?\"?$')

class FtInFormField(forms.Field):
        def clean(self,value):
                super(FtInFormField, self).clean(value)
                if value is u'' or value is None:
                        raise forms.ValidationError('Enter a dimension in X\'-Y" format')
                m = FTIN_PATTERN.match(value)
                if m is None:
                        raise forms.ValidationError('Must be in X\'-Y" Format')
                feet = int(m.group('feet'))
                inch = int(m.group('inch') or 0)
                value = '%d\'-%.0f"' % (feet,inch)
                return value

class FtInField(models.Field):
        __metaclass__ = models.SubfieldBase

        empty_strings_allowed = False

        def db_type(self):
                return 'double'

        def get_internal_type(self):
                return "FtInField"

        def to_python(self,value):
                if value is u'' or value is None:
                        return None
                if isinstance(value, float):
                        m = FTDCML_PATTERN.match(str(value))
                        if m is None:
                                raise Exception('Must be an integer or decimal number')
                        feet = int(m.group('feet'))
                        dec_inch = float(m.group('dec_inch') or 0)
                        inch = dec_inch * 12
                        return "%d\'-%.0f\"" % (feet,inch)
                return value

        def get_db_prep_value(self,value):
                if value is u'' or value is None:
                        return None
                m = FTIN_PATTERN.match(value)
                if m is None:
                        raise Exception('Must be in X\'-Y" Format')
                feet = int(m.group('feet'))
                inch = int(m.group('inch') or 0)
                return (feet + (inch/float(12)))

        def formfield(self, **kwargs):
                defaults = {'form_class': FtInFormField}
                defaults.update(kwargs)
                return super(FtInField,self).formfield(**defaults)

class ProductClass(models.Model):
        productname = models.CharField('Product Name', max_length=60,blank=True)
        depth = FtInField('Depth (Feet/Inches)')
        width = FtInField('Width (Feet/Inches)')
        height = FtInField('Height (Feet/Inches)')

class ProductClassForm(forms.ModelForm):

        class Meta:
                model = ProductClass

class ProductClassAdmin(admin.ModelAdmin):
        form = ProductClassForm
0 голосов
/ 19 декабря 2009

Чтобы избежать дублирования, вам, вероятно, следует реализовать класс типов данных, который обрабатывает для вас разборы футов и дюймов, это должно значительно упростить другой код.

Затем вы должны создать поле модели и поле формы, помня, что это два ПОЛНОСТЬЮ РАЗДЕЛЕННЫХ компонента. (что вы более или менее уже сделали, но это только для полноты)

Теперь, если я правильно читаю вопрос, вы хотите установить поле формы по умолчанию для поля модели. Чтобы облегчить это, вы хотите реализовать функцию formfield () в вашем классе поля модели. Ссылка: Документация Django

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...