我创建了一个简单的自定义MultiValueField
和MultiWidget
,用于输入出生日期,但允许分别输入日期,月份和年份。理由是该应用程序用于输入历史数据,因此这些字段中的一个或多个可能是未知的。在面向用户的网站上还有一个复选框显示“未知”。
我发现一切正常,除了当我在管理站点中保存对象的实例并创建新实例时,空白的管理表单显示了上一个条目的日期值:
所有这些字段都应空白,以用于新条目。
该字段似乎没有正确重新初始化,但是我不确定应该在哪里进行。我通过检查表单是否重新初始化字段来添加解决方法,但是我认为应该在自定义字段/窗口小部件中完成。
示例代码:
class CustomDateWidget(forms.MultiWidget):
"""Custom MultiWidget to allow saving different date values."""
template_name = 'myapp/widgets/custom_date_widget.html'
def __init__(self, attrs=None):
_widgets = (forms.NumberInput(attrs=({'placeholder': 'DD'})),
forms.NumberInput(attrs=({'placeholder': 'MM'})),
forms.NumberInput(attrs=({'placeholder': 'YYYY'})),
forms.CheckboxInput())
super().__init__(_widgets, attrs)
def decompress(self, value):
if value:
return value
else:
return '', '', '', False
def value_from_datadict(self, data, files, name):
value_list = [
widget.value_from_datadict(data, files, name + '_%s' % i)
for i, widget in enumerate(self.widgets)
]
return value_list
class CustomDateField(forms.MultiValueField):
"""Custom MultiValueField to allow saving different date values."""
def __init__(self, **kwargs):
fields = (forms.IntegerField(min_value=1, max_value=31), forms.IntegerField(min_value=1, max_value=12),
forms.IntegerField(min_value=1800, max_value=9999), forms.BooleanField())
super().__init__(fields=fields, widget=CustomDateWidget, require_all_fields=True,
**kwargs)
def compress(self, data_list):
return data_list
class PersonAdminForm(forms.ModelForm):
"""Custom Person admin form."""
date_of_birth = CustomDateField(required=False)
class Meta:
model = Person
fields = '__all__'
def __init__(self, *args, **kwargs):
super(PersonAdminForm, self).__init__(*args, **kwargs)
# Dirty workaround?
if not self.instance.pk:
self.fields['date_of_birth'] = CustomDateField(required=False)
...
小部件模板:
<style>
.custom-date-widget-container {
padding-right: 15px;
}
.custom-date-widget td {
width: 25%;
}
.custom-date-widget td > input {
width: 100%;
box-sizing: border-box;
}
</style>
{% spaceless %}
<div class="custom-date-widget-container">
<table class="custom-date-widget">
<thead>
<tr>
<th>Day</th>
<th>Month</th>
<th>Year</th>
<th>Unknown</th>
</tr>
</thead>
<tbody>
<tr>
{% for widget in widget.subwidgets %}
<td>{% include widget.template_name %}</td>
{% endfor %}
</tr>
</tbody>
</table>
</div>
{% endspaceless %}
答案 0 :(得分:2)
进一步研究之后,我发现问题不在于小部件,而在于PersonAdmin
类中。
除其他事项外,如果对象已存在,则在此处设置初始值:
def get_form(self, request, obj=None, change=False, **kwargs):
form = super(PersonAdmin, self).get_form(request, obj, **kwargs)
if obj and type(obj) == Person:
person = obj
form.base_fields['date_of_birth'].initial = [person.dob_day, person.dob_month, person.dob_year, person.dob_unknown]
我没有意识到的是,如果创建一个新对象,这些字段不会自动设置为空,而是保留以前设置的值。
添加以下内容解决了该问题:
else:
form.base_fields['date_of_birth'].initial = ['', '', '', False]
最后,它比我想象的要简单,只是我把自己送进了一个兔子洞,以为它是小部件。