Настройка того, как форма выводит поле в виджет в Django - PullRequest
3 голосов
/ 27 августа 2009

У меня есть настраиваемое поле с именем HourField, которое позволяет вам ввести «1:30», чтобы обозначить полтора часа. Метод clean() превращает его в 1,5 для FloatField в модели. Это все отлично работает. Теперь у меня проблема, когда я хочу создать набор форм, это поле отображается как «1.5» вместо «1:30», что мне и нужно.

Есть ли какой-то метод, похожий на clean(), но работает наоборот?

edit: использование другого типа хранилища исключено. У меня есть несколько других пользовательских полей, которые хранятся как один тип объекта, но вводятся пользователем в виде строки. Я использовал приведенный выше пример, потому что он был самым прямым.

Ответы [ 4 ]

3 голосов
/ 31 августа 2009

Чтобы настроить способ визуализации поля, вам также необходимо определить виджет.

Следующий код показывает некоторые обязанности виджетов в django:

  • рендеринг тега формы (суперкласс TextInput позаботится об этом)
  • форматировать значение для отображения внутри поля формы. здесь есть ошибка: класс значения может варьироваться, поскольку вы можете отображать очищенные значения, поступающие из поля, или неочищенные данные, поступающие из формы POST. Следовательно, проверьте, есть ли у нас числовое значение в _format_value; если это строка, просто оставьте ее как есть.
  • сообщить, изменилось ли значение по сравнению с исходными данными. Очень важно, когда вы используете формы со значениями по умолчанию.

Обратите внимание, что код виджета основан на widgets.TimeInput из исходного кода django, что помогает быть последовательным.

from django import forms
from django.forms import widgets
from django.forms.util import ValidationError

class HourWidget(widgets.TextInput):

    def _format_value(self, value):
        if isinstance(value, float) or isinstance(value, int):
            import math

            hours = math.floor(value)
            minutes = (value - hours) * 60
            value = "%d:%02d" % (hours, minutes)

        return value

    def render(self, name, value, attrs=None):
        value = self._format_value(value)
        return super(HourWidget, self).render(name, value, attrs)

    def _has_changed(self, initial, data):
        return super(HourWidget, self)._has_changed(self._format_value(initial), data)

class HourField(forms.Field):
    widget = HourWidget

    def clean(self, value):
        super(HourField, self).clean(value)

        import re
        match = re.match("^([0-9]{1,2}):([0-9]{2})$", value)
        if not match:
            raise ValidationError("Please enter a valid hour ( ex: 12:34 )")

        groups = match.groups()
        hour = float(groups[0])
        minutes = float(groups[1])

        if minutes >= 60:
            raise ValidationError("Invalid value for minutes")

        return hour + minutes/60

Обратите внимание, что 1:20 становится 1:19, что связано с потерей точности, вызванной использованием поплавка. Возможно, вы захотите изменить тип данных, если не хотите терять точность.

1 голос
/ 27 августа 2009

Ответственность за отображение данных в поле формы лежит на виджете. Похоже, вам нужно определить пользовательский виджет, который реализует метод render(), который принимает десятичное значение поля и выводит его, как вы хотите.

К сожалению, по-видимому, нет документации по созданию пользовательских виджетов, но вы можете посмотреть в коде django.forms.extras.widgets пример того, как это сделать.

1 голос
/ 30 августа 2009
from django.forms.widgets import TextInput

class TimeInput(TextInput):
     def _format_value(self, value):
         """Convert float to time"""
         if not value:
             return ''
         fraction, integer = math.modf(value)
         minutes = 0 if fraction == 0 else .6 / fraction
         return "%d:%02d" % (int(integer), int(minutes))

     def render(self, name, value, attrs=None):
        value = self._format_value(value)
        return super(TimeInput, self).render(name, value, attrs)
0 голосов
/ 27 августа 2009

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

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