自定义 django 小部件 - decompress() arg 未填充
Posted
技术标签:
【中文标题】自定义 django 小部件 - decompress() arg 未填充【英文标题】:Custom django widget - decompress() arg not populated 【发布时间】:2010-10-07 02:18:13 【问题描述】:作为练习,我正在尝试为 24 小时制创建一个自定义 django 小部件。小部件将是一个 MultiWidget - 每个字段的选择框。
我正在尝试在线关注文档(有点稀疏)并查看 Pro Django 书,但我似乎无法弄清楚。我在正确的轨道上吗?我可以保存表单中的数据,但是当我预填充表单时,表单没有以前的值。
问题似乎在于 decompress() 方法的“值”参数始终为空,所以我没有什么要解释的。
from django.forms import widgets
import datetime
class MilitaryTimeWidget(widgets.MultiWidget):
"""
A widget that displays 24 hours time selection.
"""
def __init__(self, attrs=None):
hours = [ (i, "%02d" %(i)) for i in range(0, 24) ]
minutes = [ (i, "%02d" %(i)) for i in range(0, 60) ]
_widgets = (
widgets.Select(attrs=attrs, choices=hours),
widgets.Select(attrs=attrs, choices=minutes),
)
super(MilitaryTimeWidget, self).__init__(_widgets, attrs)
def decompress(self, value):
print "******** %s" %value
if value:
return [int(value.hour), int(value.minute)]
return [None, None]
def value_from_datadict(self, data, files, name):
hour = data.get("%s_0" %name, None)
minute = data.get("%s_1" %name, None)
if hour and minute:
hour = int(hour)
minute = int(minute)
return datetime.time(hour=hour, minute=minute)
return None
在我的表单中,我将小部件称为:
arrival_time = forms.TimeField(label="Arrival Time", required=False, widget=MilitaryTimeWidget())
【问题讨论】:
我不会把它作为答案,因为它与你的问题正交:但我想不出你为什么想要这个 UI。这比您在表单中正确解析/验证的文本输入框更好/更快/更容易吗? 【参考方案1】:注意this line in the docstring for MultiWidget:
您可能希望将此类与 MultiValueField 一起使用。
这是你问题的根源。您也许可以让仅使用单个小部件的方法发挥作用(Marty 说这在 Pro Django 中是可能的,但我从未尝试过,而且我认为这可能需要更多工作),但是在这种情况下,您的小部件不应该是 MultiWidget 的子类。
你需要做的(如果你想遵循 MultiWidget/MultiValueField 路径)是:
删除您的 value_from_datadict 方法 定义 MultiValueField 的子类,并定义 compress() 方法,该方法执行您当前在 value_from_datadict() 中执行的任务(将数字列表转换为 datetime.time 对象) 将小部件设置为自定义表单字段的默认小部件(使用小部件类属性) 要么创建一个自定义模型字段,该字段从其 formfield() 方法返回您的自定义表单字段,要么手动使用您的自定义表单字段作为 ModelForm 中的字段覆盖。然后一切都会正常工作。
【讨论】:
看起来 django.forms.fields.SplitDateTimeField 和 django.forms.widgets.SplitDateTimeWidget 是很好的模型基础。【参考方案2】:我无法重现该问题:
>>> class MyForm(forms.Form):
... t = forms.TimeField(widget=MilitaryTimeWidget())
...
>>> print MyForm(data='t_0': '13', 't_1': '34')
******** 13:34:00
<tr><th><label for="id_t_0">T:</label></th><td><select name="t_0" id="id_t_0">
<option value="0">00</option>
[...]
<option value="13" selected="selected">13</option>
[...]
<option value="23">23</option>
</select><select name="t_1" id="id_t_1">
<option value="0">00</option>
[...]
<option value="34" selected="selected">34</option>
[...]
<option value="59">59</option>
</select></td></tr>
检查您的 request.POST 是否正确。
作为旁注,您确定这个小部件具有良好的可用性吗?四次鼠标点击和分钟组合框的可能滚动...
【讨论】:
我认为我的问题是我没有尝试使用 POST 数据填充表单,而是尝试使用我的模型之一进行填充。由于我在传入的数据中缺少到达时间_0 和到达时间_1(每个选择小部件的名称),因此它没有被填充。 在传递到表单之前故意在我的视图中拆分该数据似乎相当笨拙且非pythonic。想法?以上是关于自定义 django 小部件 - decompress() arg 未填充的主要内容,如果未能解决你的问题,请参考以下文章
Django:如何检查自定义小部件定义中是不是存在字段错误?