【问题标题】:How to serialize cleaned_data if it contains models?如果clean_data包含模型,如何序列化它?
【发布时间】:2011-09-13 11:34:01
【问题描述】:

我正在尝试序列化一些表单数据,以便将其填充到隐藏字段中,直到用户准备好提交整个表单(想想向导)。

我正在尝试这个:

print simplejson.dumps(vehicle_form.cleaned_data)

但我不断收到这样的错误:

<VehicleMake: Honda> is not JSON serializable

真的,我只需要它来输出“本田”的PK。

这也不起作用:

print serializers.serialize('json', vehicle_form.cleaned_data)

给予:

'str' object has no attribute '_meta'

大概是因为它正在遍历所有字符串的键,而我认为它需要一个我没有的查询集。

那么我该怎么做呢?


好的,到目前为止我已经想出了这个:

from django.utils.simplejson import JSONEncoder, dumps, loads
from django.utils.functional import curry
from django.db.models import Model
from django.db.models.query import QuerySet
from django.core.serializers import serialize

class DjangoJSONEncoder(JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Model):
            return obj.pk
        elif isinstance(obj, QuerySet):
            return loads(serialize('json', obj, ensure_ascii=False))
        return JSONEncoder.default(self, obj)

json_encode = curry(dumps, cls=DjangoJSONEncoder)
json_decode = loads

根据我在 [此处][1] 找到的答案。现在我正在尝试这个:

json = json_encode(vehicle_form.cleaned_data)
data = json_decode(json)
vehicle = Vehicle(**data)

前 2 行完美运行,但第 3 行导致异常:

Cannot assign "3": "Vehicle.model" must be a "VehicleModel" instance.

越来越近了!虽然不知道如何处理这个......

【问题讨论】:

    标签: django json serialization


    【解决方案1】:

    这有点小技巧,但我不知道更好的方法:

    try:
        vehicle_data = simplejson.loads(request.POST['vehicle_data'])
    except ValueError:
        vehicle_data = []
    vehicle_data.append(vehicle_form.raw_data())
    request.POST['vehicle_data'] = simplejson.dumps(vehicle_data)
    

    它从表单中的隐藏字段中获取 JSON 数据并将其解码为 Python 字典。如果它不存在,它会启动一个新列表。然后它附加新的原始/未清理数据并重新编码并将其转储到隐藏字段中。

    为此,您需要复制 POST 数据 (request.POST.copy()) 以使其可变,或者像我一样破解它:request.POST._mutable = True

    在我的表单模板中我把这个:

    <input type="hidden" name="vehicle_data" value="{{request.POST.vehicle_data}}" />
    

    最后,为了访问表单的原始数据,我添加了以下方法:

    from django.forms import *
    
    def _raw_data(self):
        return dict((k,self.data[self.add_prefix(k)]) for k in self.fields.iterkeys())
    
    def _raw_value(self, key, value=None):
        if value is None:
            return self.data[self.add_prefix(key)]
        self.data[self.add_prefix(key)] = value
    
    Form.raw_data = _raw_data
    Form.raw_value = _raw_value
    ModelForm.raw_data = _raw_data
    ModelForm.raw_value = _raw_value
    

    由于.data 返回的数据太多(实际上,它只是返回您最初传入的 POST 数据),而且它还有前缀,这是我不想要的。

    【讨论】:

    • 哇,有很多黑客攻击 =) 你检查过 django-formwizard (django-formwizard.readthedocs.org) 吗?它基本上允许您指定一系列表单并处理步骤之间的数据存储。如果你有多个模型实例,你也可以在那里有一个 ModelForm,或者一个 formset。
    • @Anton:嗯...这不是一个真正的巫师,这只是解释它的最简单方法。实际上,它是一个带有子表单的表单,您可以在其中添加任意数量的项目。当您单击“添加”时,它会将所有数据发布回同一页面,将子表单数据序列化为隐藏字段并将其清除,以便您可以添加另一个。因此,您有一个无 JS 的“动态”表单,您可以在其中添加任意数量的项目。很酷的海事组织。这并不是 hacky......它实际上是一个非常干净的解决方案,与我之前尝试的那些相反。
    • @Anton:那个页面上的“内容”列表……我花了一段时间才意识到那些是链接。与普通文本相同的颜色,并且在悬停之前没有下划线..hrm.. 另外,与 django 附带的相比,它有什么优势? docs.djangoproject.com/en/dev/ref/contrib/formtools/form-wizard
    • 嗯,django-formwizard 实际上会变成contrib.formtools.wizard,所以如果你使用的是最新的 Django 开发版本,那么我猜你已经可以使用它了。但是,如果您坚持使用稳定版本的 Django,请使用 django-formwizard 应用程序(旧的 contrib formwizard 不好)。
    • @Anton:哦。很公平。是的,我现在正在运行稳定的 1.3。
    猜你喜欢
    • 2019-05-17
    • 1970-01-01
    • 2018-03-01
    • 2020-08-01
    • 1970-01-01
    • 2021-11-01
    • 1970-01-01
    • 2023-04-06
    • 1970-01-01
    相关资源
    最近更新 更多