【问题标题】:Pass json and deserialize form in django在 django 中传递 json 和反序列化表单
【发布时间】:2015-07-08 21:33:51
【问题描述】:

接下来是问题:我使用 ajax 向服务器发送了一些发布数据。此数据如下所示:

data = {
  form : $(this).serialize(),
  some_array: [2,3,4,1]
}

如何在 django 中获取表单对象? request.POST['form'] 返回带有表单的字符串。我正在尝试使用import json 库。

但是,当我跑步时 value = json.load(request.POST['some_array'])form = json.load(request.POST['form']) 它不起作用。

打印request.POST['form'] 会返回以下内容:

u'csrfmiddlewaretoken=I3LWAjfhZRGyd5NS3m9XcJkfklxNhxOR& address_city=%D0%9A%D0%B8%D1%97%D0%B2& address_street=2& address_building=3& delivery_time=2015-05-15'

【问题讨论】:

  • 去除代码中多余的缩进并在内容中添加一些空格

标签: json django django-forms django-serializer


【解决方案1】:

表单数据不是以 JSON 编码,而是作为查询字符串编码。 您可以使用标准库中的urlparse.parse_qs 来解析该查询字符串。

例子:

from urlparse import parse_qs


form_data = parse_qs(request.POST['form'].encode('ASCII'))  # Query strings use only ASCII code points so it is safe.

# To access address_city:
address_city = form_data['address_city'][0].decode('utf-8')

# If you plan to pass form_data to a Django Form,
# use QueryDict instead of parse_qs:
from django.http import QueryDict


form_data = QueryDict(request.POST['form'].encode('ASCII'))

【讨论】:

  • 您知道将一些数据与表单数据一起发送的正确方法吗?因为,如果我按照上面描述的那样做,我的表单字段看起来有点奇怪,例如如果我只发送表单,则 form.cleaned_data['address_city'] 返回 Kyiv,但是当我将表单作为查询字符串发送时,form.cleaned_data['address_city'] 看起来像 u'[u\\'\\xd0\\x9a\\xd0\\xb8\\xd1\\x97\\xd0\\xb2\\']'
  • @Andrew 我编辑了我的答案以考虑字符串编码。 parse_qs 需要一个字节字符串作为输入,而不是一个 unicode 对象。
  • 2021 这对我来说就像一个魅力。谢谢老哥!
【解决方案2】:

解决方案 1

除了 aumo 的回答,假设您使用的是 jQuery,您实际上可能想要使用 .serializeArray() 而不是 .serialize(),来生成一个 JSON 对象,然后您可以使用 JSON.stringify 和 POST。

data = {
  form : $(this).serializeArray(),
  some_array: [2,3,4,1]
};

$.ajax(url, {
  data: JSON.stringify(data),
  contentType: 'application/json',
  type: 'POST',
});

正如您在 cmets 中指出的那样,serializeArray JSON 输出的格式不容易被 Django 表单使用,在通过 json.load 反序列化内容后需要进一步处理。

data = json.load(request)
value = data['some_array']

form_data = {}
for f in data['form']:
    if f not in form_data:
        form_data[f['name']] = f['value']
    elif not isinstance(form_data[f['name']], list):
        form_data[f['name']] = [form_data[f['name']], f['value']]
    else:
        form_data[f['name']].append(f['value'])

form = MyForm(data=form_data)

解决方案 2

再次查看代码后,在前端将表单数据序列化为正确的 json 格式可能会更好(并且更通用以确保未来安全)。

虽然对此有很多解决方案;我最好的选择是使用诸如jquery-serialize-object 之类的久经考验/流行的库,代码更改会很小:

<script src="jquery.serialize-object.min.js"></script>
<script>
    data = {
      form : $(this).serializeObject(),
      some_array: [2,3,4,1]
    };

    $.ajax(url, {
      data : JSON.stringify(data),
      contentType : 'application/json',
      type : 'POST',
    });
</script>

然后服务器代码会简单得多

data = json.load(request)
value = data['some_array']
form = MyForm(data=data['form'])

【讨论】:

  • 问题是 serializeArray 返回一个 array{name: ..., value: ...} 映射)不是名称 -> 值的映射,因此行为不同,需要额外的处理服务器边。另一件事,request.body 是一个字符串(字节),所以你必须使用json.loads,不过你可以使用json.load(request)
  • 我喜欢json.load(request),我忘了HttpRequest implements iter。您对serializeArray 的看法是绝对正确的,我已经更新了我的示例;尽管您可以轻松地创建一个 JSON 对象,并将名称作为属性或 use an existing solution
  • 唯一剩下的问题是,如果您有多个具有相同名称值的条目,则最后一个值会覆盖其他值。例如,此代码不适用于多选。 (是的,我越来越无聊了)
  • 你让我明白了,我倾向于更倾向于发布“已经正确格式化的 json”的解决方案(使前端模板更通用/独立于服务器)。详情请参考jquery-serialize-object
猜你喜欢
  • 2011-09-17
  • 2016-04-16
  • 1970-01-01
  • 2011-06-30
  • 2018-12-18
相关资源
最近更新 更多