我一直在拉我的头发来完成这件事。我的一个模型中有2个整数字段,如下所示:
#models.py
class TestModel(models.Model):
"""
This is a test model.
"""
max = models.IntegerField()
min = models.IntegerField()
由于以上两个值是相互关联的,我希望他们使用自定义小部件。现在重点是,我希望这些字段使用单个自定义窗口小部件(MultiWidget),但我也希望将值保存在数据库的不同列中[不要真正想解析内容,而且搜索功能将使用以上字段分开,所以只想单独存储]。
自定义窗口小部件只接受来自单个模型字段的值,因此我决定创建一个自定义窗体域,以便在ModelForm中用于上述模型。
现在这就是我的表格。
class MinMaxField(forms.MultiValueField):
def __init__(self, *args, **kwargs):
all_fields = (
forms.CharField(),
forms.CharField(),
)
super(MinMaxField, self).__init__(all_fields, *args, **kwargs)
def compress(self, values):
if values:
return '|'.join(values)
return ''
class TestModelForm(forms.ModelForm):
minmax = MinMaxField(widget=widgets.MinMaxWidget(),
required=False)
class Meta:
model = models.TestModel
fields = ('min', 'max', 'minmax')
widgets = {
'min' : forms.HiddenInput(),
'max' : forms.HiddenInput(),
}
def full_clean(self, *args, **kwargs):
if 'minmax_0' in self.data:
newdata = self.data.copy()
newdata['min'] = self.data['minmax_0']
newdata['max'] = self.data['minmax_1']
self.data = newdata
super(TestModelForm, self).full_clean(*args, **kwargs)
上面的表单基本上隐藏了模型字段,并且只显示了使用自定义窗口小部件的minmax
字段,如下所示:
class MinMaxWidget(widgets.MultiWidget):
def __init__(self, attrs=None):
mwidgets = (widgets.Select(attrs=attrs, choices=MIN),
widgets.Select(attrs=attrs, choices=MAX))
super(MinMaxWidget, self).__init__(mwidgets, attrs)
def value_from_datadict(self, data, files, name):
try:
values = [widget.value_from_datadict(data, files, name + '_%s' % i)\
for i, widget in enumerate(self.widgets)]
value = [int(values[0]), int(values[1])]
except ValueError:
raise ValueError('Value %s for %s did not validate. \
a list or a tuple expected' % (value, self.widget))
return value
def decompress(self, value):
if value:
if isinstance(value, list):
return value
return [value[0], value[1]]
return [None, None]
def format_output(self, rendered_widgets):
rendered_widgets.insert(0, '<span class="multi_selects">')
rendered_widgets.insert(-1, '<label id="min">Min</label>')
rendered_widgets.append('<label id="max">Max</label></span>')
return u''.join(rendered_widgets)
现在,此时一切正常,值会分别保存到各自的字段中。但是,当我尝试使用TestModel
对象的实例编辑表单时,问题就出现了。在编辑的情况下,在呈现表单时,实际值存储在隐藏的min
和max
输入字段中,而minmax字段没有值。 [当然,因为它是一个表格领域。]
我有什么选择
预先填充minmax
和min
字段中max
表单字段的值。 [注意:不使用Javascript或jQuery]
或者创建一个使用两个不同模型字段中的值的MultiWidget。
任何帮助将不胜感激。感谢。
答案 0 :(得分:0)
我目前遇到类似的问题,并且有一种方法可以将窗口小部件用于两个字段。 我使用的是1.4版,并没有尝试过任何其他版本。
在您看来,您可能会遇到以下情况:
form = TestModelForm(instance=instance)
其中instance
是您要编辑的数据库中的对象。
让我们看看Django在创建表单时正在做什么
# django/forms/models.py
class BaseModelForm(BaseForm):
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
initial=None, error_class=ErrorList, label_suffix=':',
empty_permitted=False, instance=None):
...
if instance is None:
...
else:
self.instance = instance
object_data = model_to_dict(instance, opts.fields, opts.exclude)
# if initial was provided, it should override the values from instance
if initial is not None:
object_data.update(initial)
...
super(BaseModelForm, self).__init__(data, files, auto_id, prefix,
object_data, error_class,
label_suffix, empty_permitted)
然后,在呈现表单时,BoundField
类使用此object_data
为窗口小部件分配初始值。
因此,您需要做的就是在表单构造函数中提供initial
。
class TestModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
if 'instance' in kwargs:
initial = dictionary with initial values
initial.update(kwargs['initial'] or {})
...
super(TestModelForm, self).__init__(initial=initial, *args, **kwargs)
另请记住将您的字段添加到表单fields
列表中。
这样你就没有两个未使用的隐藏小部件,不需要使用javascript和imo,代码更具说明性。