Django自定义MultiWidget保留旧值

时间:2019-05-07 08:20:15

标签: python django

我创建了一个简单的自定义MultiValueFieldMultiWidget,用于输入出生日期,但允许分别输入日期,月份和年份。理由是该应用程序用于输入历史数据,因此这些字段中的一个或多个可能是未知的。在面向用户的网站上还有一个复选框显示“未知”。

我发现一切正常,除了当我在管理站点中保存对象的实例并创建新实例时,空白的管理表单显示了上一个条目的日期值:

Custom 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 %}

1 个答案:

答案 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]

最后,它比我想象的要简单,只是我把自己送进了一个兔子洞,以为它是小部件。