要定製字段呈現的方式,您還需要定義一個小部件。
下面的代碼顯示窗口小部件的一些職責在Django:
- 呈現形式標籤(超類的TextInput照顧的這個)
- 格式表單字段內顯示的值。 這裏有一個問題:值的類可能會有所不同,因爲您可能會呈現來自該字段的清理值或來自表單POST的未清理數據。因此,測試在_format_value中是否有數值;如果它是一個字符串,就把它保持原樣。
- 確定該值是否與初始數據相比發生了變化。使用默認值的表單集非常重要。
請注意,widget的代碼受django源代碼中widgets.TimeInput的啓發,這有助於保持一致。
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,這是由於使用浮動引起的精度損失。如果你不想失去一些精度,你可能想要改變數據類型。
_format_value()中的%1d不會像10,11和12那樣截斷小時嗎? – 2009-08-31 14:01:54
「1」是'width'參數,它僅用於填充,不用於截斷;也就是說,字符被添加到左側,從未刪除。 %運算符的行爲與sprintf相似(http://en.wikipedia.org/wiki/Printf#printf_format_placeholders)。 您不能用這種方法截斷數字的整數部分。只能使用精度參數截斷小數部分(「%.2f」%0.123 ==「0.12」)。 使用字符串格式的精度參數可能會發生截斷:「%.1s」%123 ==「1」 – vincent 2009-08-31 14:23:00
順便說一下,雖然它沒有引入錯誤,但我同意'%1d'是無用的,因爲任何數字總會在整數部分產生至少一個字符:-)我寫這個是因爲我以「%2d:%2d」開頭,並且在小時部分只需要1個字符。 – vincent 2009-08-31 21:17:47