Django JSONField не получает очищенные данные - PullRequest
0 голосов
/ 12 февраля 2019

У меня очень простая модель, которая содержит JSONField:

class Thing(models.Model):
    title = models.CharField(max_length=1024)
    text = JSONField(default=dict)

Я создал собственный виджет, который позволяет вводить пары ключ-значение:

class JsonWidget(forms.widgets.Widget):
    template_name = 'json_widget.html'

    def get_context(self, name, value, attrs):
        context = super().get_context(name, value, attrs)
        data = json.loads(value)
        if not data:
            data = JSON_DEFAULT
        context['data'] = data.items()
        return context

    def value_from_datadict(self, data, files, name):
        keys = data.getlist('json-key')
        values = data.getlist('json-value')
        json_data = {k: v for k, v in zip(keys, values)}
        return json_data

Я принудительно возвращаю dict, возвращаемый виджетом, в строку в функции clean поля в форме:

class ThingForm(forms.ModelForm):

    class Meta:
        model = Thing
        fields = ['title', 'text']
        widgets = {
            'text': JsonWidget(),
        }

    def clean_text(self):
        text = self.cleaned_data.get('text')
        return json.dumps(text)

Я проверил вывод JsonWidget.value_from_datadict (dictThingForm.clean_text (str) - ожидаемые типы.Но когда объект идет на сохранение, он выдает исключение:

TypeError: the JSON object must be str, bytes or bytearray, not 'dict'

Это мой первый раз, когда я создаю собственный виджет для Django 1.11, есть ли что-то очевидное, что я здесь упустил?

Спасибо!

1 Ответ

0 голосов
/ 13 февраля 2019

Это было непросто, но я в конечном итоге отследил проблему до Сбой построения экземпляра при проверке данных формы

Хотя JSONField называется text в модели, естьнет соответствующего поля на ModelForm.Вместо этого пары ключ / значение компилируются и превращаются в dict с помощью value_from_datadict виджета.Однако значения cleaned_data сохраняются обратно в экземпляр только , если имя поля существует в данных POST формы.Это заставило виджет выдать ошибку, потому что text не мог быть пустым, а исключение TypeError было вызвано во время повторного рендеринга формы.

Обходной путь - добавить скрытый ввод с именем textв поле и только использовать его для обхода проверки имени поля во время создания.

...