0

我有一个非常简单的模型,其中包含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( dict) 和ThingForm.clean_text( str) 的输出是预期的类型。但是当对象去保存它抛出一个异常:

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

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

谢谢!

4

1 回答 1

0

这是一个棘手的问题,但我最终将问题追溯到表单数据检查中的实例构造失败

在模型JSONField上调用text时,在 上没有匹配字段ModelForm。相反,键/值对dict由小部件的value_from_datadict. 但是,只有当字段名称存在于表单的 POST 数据中时,这些cleaned_data值才会保存回实例。这导致小部件由于不能为空白而引发错误,并且在表单重新渲染期间引发了异常。textTypeError

解决方法是text向该字段添加一个隐藏输入,并在实例化期间使用它来绕过字段名称检查。

于 2019-02-13T03:42:50.763 回答