创建一个使用两个 <input> 的自定义 Django 表单字段
我想知道怎么在Django里创建一个字段,让它显示成一对输入框。
原因是:我想写一个新的自定义字段,打算用它来做一个类似验证码的服务。这个服务的工作方式是先请求一个问题,然后收到一个问题和一个令牌。验证的过程是把答案和令牌一起发送过去。我想写一个表单字段,把这个逻辑封装起来。这个字段的显示方式应该像这样:
<input type="hidden" name="_token" value="1234567890" />
<input type="text" name="answer" />
在提交的时候,我需要_token
和答案
的值来验证答案。
3 个回答
4
这里有一个现成的例子(来自我的博客):
class ComplexMultiWidget(forms.MultiWidget):
def __init__(self, attrs=None):
widgets = (
forms.TextInput(),
forms.SelectMultiple(choices=(('J', 'John'),
('P', 'Paul'),
('G', 'George'),
('R', 'Ringo'))),
forms.SplitDateTimeWidget(),
)
super(ComplexMultiWidget, self).__init__(widgets, attrs)
def decompress(self, value):
if value:
data = value.split(',')
return [data[0], data[1],
datetime.datetime(*time.strptime(data[2],
"%Y-%m-%d %H:%M:%S")[0:6])]
return [None, None, None]
def format_output(self, rendered_widgets):
return u'\n'.join(rendered_widgets)
class ComplexField(forms.MultiValueField):
def __init__(self, required=True, widget=None, label=None, initial=None):
fields = (
forms.CharField(),
forms.MultipleChoiceField(choices=(('J', 'John'),
('P', 'Paul'),
('G', 'George'),
('R', 'Ringo'))),
forms.SplitDateTimeField()
)
super(ComplexField, self).__init__(fields, required,
widget, label, initial)
def compress(self, data_list):
if data_list:
return '%s,%s,%s' % (data_list[0],''.join(data_list[1]),
data_list[2])
return None
使用示例:
>>> f = ComplexField(widget=ComplexMultiWidget())
>>> f.clean(['some text', ['J','P'], ['2007-04-25','6:24:00']])
u'some text,JP,2007-04-25 06:24:00'
>>> f.clean(['some text',['X'], ['2007-04-25','6:24:00']])
Traceback (most recent call last):
...
ValidationError: [u'Select a valid choice. X is not one of the available choices.']
>>> f.clean(['some text',['JP']])
Traceback (most recent call last):
>>> class ComplexFieldForm(Form):
field1 = ComplexField(widget=ComplexMultiWidget())
>>> f = ComplexFieldForm({'field1_0':'some text','field1_1':['J','P'], 'field1_2_0':'2007-04-25', 'field1_2_1':'06:24:00'})
>>> print f
<tr><th><label for="id_field1_0">Field1:</label></th><td><input type="text" name="field1_0" value="some text" id="id_field1_0" />
<select multiple="multiple" name="field1_1" id="id_field1_1">
<option value="J" selected="selected">John</option>
<option value="P" selected="selected">Paul</option>
<option value="G">George</option>
<option value="R">Ringo</option>
</select>
<input type="text" name="field1_2_0" value="2007-04-25" id="id_field1_2_0" /><input type="text" name="field1_2_1" value="06:24:00" id="id_field1_2_1" /></td></tr>
>>> f.cleaned_data
{'field1': u'some text,JP,2007-04-25 06:24:00'}
9
我觉得你在找的是 MultiWidget。你只需要给它两个普通的小部件,它就会把这两个组合起来显示。
2
看看这个 SelectDateWidget。它把日期的输入分成了三个选择框。
文档说明里提到:
这也是一个示例,展示了一个有多个HTML元素的组件,因此它实现了
value_from_datadict
。