Django JSONField不接收清理的数据

时间:2019-02-12 07:30:02

标签: django django-forms django-widget django-jsonfield

我有一个非常简单的模型,其中包含一个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_datadictdict)和ThingForm.clean_textstr)的输出是预期的类型。但是当对象要保存时,它将引发异常:

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

这是我第一次为Django 1.11构建自定义小部件,在这里我错过了明显的东西吗?

谢谢!

1 个答案:

答案 0 :(得分:0)

这是一个棘手的问题,但我最终将问题追溯到Instance construction fails on form data check

虽然模型上的JSONField被称为text,但是ModelForm上没有匹配字段。而是将键/值对编译并通过小部件的dict转换为value_from_datadict。但是,如果字段名称存在于表单的POST数据中,则cleaned_data值将被保存回实例 only 。这导致窗口小部件引发错误,因为text不能为空,并且在表单重新呈现期间引发了TypeError异常。

解决方法是在字段中添加一个名为text的隐藏输入,并且仅 使用它在实例化过程中绕过字段名称检查。