Пользовательский мультивиджет Django, сохраняющий старые значения - PullRequest
5 голосов
/ 07 мая 2019

Я создал простой пользовательский MultiValueField и MultiWidget с целью ввода даты рождения, но с возможностью отдельного ввода дня, месяца и года.Смысл в том, что приложение предназначено для ввода исторических данных, поэтому одно или несколько из этих полей могут быть неизвестны.Существует также флажок, который отображает «неизвестный» на сайте, обращенном к пользователю.

Я обнаружил, что все работает нормально, за исключением того, что когда я сохраняю экземпляр объекта на сайте администратора и перехожу к созданиюВ новом экземпляре в пустой форме администратора отображаются значения даты из предыдущей записи:

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 Ответ

2 голосов
/ 12 мая 2019

После некоторого дальнейшего поиска я обнаружил, что проблема была не в виджете, а в классе 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]

В конце концов это оказалось проще, чем я думал, просто я спустился в кроличью нору, думая, что это виджет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...