Ajax与Python操作JSON数据
JSON的基本概念
基本概念
JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
JSON 是轻量级的文本数据交换格式
JSON 独立于语言 *
JSON 具有自我描述性,更易理解
JSON与Python
json数据类型和python数据类型的对比:
object和python的dict类型是差不多的,但是要求里面必须是双引号,string和list、tuple等也是一样的,都是双引号。
但是要注意:python中的datetime等时间日期类型是不能进行json序列化的,因为json没有对应的格式,上面的这几种数据类型虽然进行json.dumps序列化之后都是个字符串,但是也是有格式的!
前端ajax拿到后端返回的一个python的json模块序列化之后的一个json字符串,那么js通过自己的json接口,将接受到的json字符串来反序列化为js自己语言能够识别的数据类型,然后再进行操作。
相当于我有一个json方法,你有一个json方法,你给我发数据必须是json字符串的格式,那么你就需要将你的数据类型序列化为json的字符串,那么序列化的时候,就把你的数据序列化为了符合json标准的字符串,然后我接收到这个字符串之后,我通过我的json方法,将数据转换为我的语言支持的数据类型。在进行反序列化的时候,如果你的字符串不符合json的格式,那么反序列化的时候就会报错,所以只要你是通过json序列化成的字符串,都是能够json反序列化的,因为json序列化的时候,就把你的数据改为了符合json标准的字符串形式,例如:里面的单引号,序列化后变成了双引号。
合格的json对象:
["one", "two", "three"] { "one": 1, "two": 2, "three": 3 } #这就是一个json的object类型,符合json的标准格式,就可以通过dumps来进行序列化 {"names": ["whw", "naruto"] } [ { "name": "whw"}, {"name": "naruto"} ]
不合格的json对象:
{ name: "whw", 'age': 22 } #属性名必须使用双引号 [32, 64, 128, 0xFFF] #不能使用十六进制值 { "name": "whw", "age": undefined } #不能使用undefined { "name": "whw", "birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'), "getName": function() {return this.name;} #不能使用函数和日期对象 }
普通字符串和json字符串,在进行序列化的时候的区别
import json # s = "{'name':'whw','age':18}" #普通字符串,每加引号的没问题,加了引号的,必须是双引号才能使用json.loads()。 s = '{"name":"whw","age":18}' #json字符串,里面必须是双引号 ret = json.loads(s) print(ret) print(ret['name'])
JSON与JS
js的stringify与parse方法
JavaScript中关于JSON对象和字符串转换的两个方法:
JSON.parse()
用于将一个 JSON 字符串转换为 JavaScript 对象
JSON.parse('{"name":"whw"}'); //正确 JSON.parse('{name:"whw"}') ; //错误 JSON.parse('[18,undefined]') ; //错误
JSON.stringify()
用于将 JavaScript 值转换为 JSON 字符串
JSON.stringify({"name":"whw"})
JSON与XML
JSON 格式于2001年由 Douglas Crockford 提出,目的就是取代繁琐笨重的 XML 格式。
JSON 格式有两个显著的优点:书写简单,一目了然;符合 JavaScript 原生语法,可以由解释引擎直接处理,不用另外添加解析代码。所以,JSON迅速被接受,已经成为各大网站交换数据的标准格式,并被写入ECMAScript 5,成为标准的一部分。
XML和JSON都使用结构化方法来标记数据,下面来做一个简单的比较。
用XML与JSON分别表示中国部分省市数据如下:
<?xml version="1.0" encoding="utf-8"?> <country> <name>中国</name> <province> <name>黑龙江</name> <cities> <city>哈尔滨</city> <city>大庆</city> </cities> </province> <province> <name>广东</name> <cities> <city>广州</city> <city>深圳</city> <city>珠海</city> </cities> </province> <province> <name>台湾</name> <cities> <city>台北</city> <city>高雄</city> </cities> </province> <province> <name>新疆</name> <cities> <city>乌鲁木齐</city> </cities> </province> </country>
{ "name": "中国", "province": [{ "name": "黑龙江", "cities": { "city": ["哈尔滨", "大庆"] } }, { "name": "广东", "cities": { "city": ["广州", "深圳", "珠海"] } }, { "name": "台湾", "cities": { "city": ["台北", "高雄"] } }, { "name": "新疆", "cities": { "city": ["乌鲁木齐"] } }] }
由上面的两段代码可以看出,JSON 简单的语法格式和清晰的层次结构明显要比 XML 容易阅读,并且在数据交换方面,由于 JSON 所使用的字符要比 XML 少得多,可以大大得节约传输数据所占用的带宽。
Ajax和Python后台服务端的数据交互时的序列化问题
当我们在后台给ajax的回调函数回复的不是一个字符串,而是其他数据类型的时候,需要我们将数据转换为json字符串进行发送,这样好配合js进行json字符串的处理,不然发送或者接受的是普通字符串的话,没办法处理成原来的数据类型。
在后台我们有三种方法去解决前后端数据在交互时序列化的问题:
方法一
后台HttpReaponse前将前端需要的数据序列化成JSON格式的数据;ajax的回调函数接收这个JSON格式的数据后再进行JS的反序列化拿到自定义对象去处理。
这种方式相对来说比较麻烦,因为需要前后端都要进行序列化与反序列化的操作。
方法二
后台HttpReaponse前将前端需要的数据序列化成JSON格式的数据,然后在提交数据的时候把自己的content_type参数设置成‘application/json’就可以了。
HttpResponse(json.dumps({'name';'chao'}),content_type='application/json')
利用这种方式,前端ajax的回调函数收到的就是一个自定义对象,不用进行反序列化操作了~
方法三(常用)
利用django内置的JsonResponse方法返回。
from django.http import JsonResponse ... return JsonResponse({'name';'whw'})
其实这种方法是前两种方法的结合~
但是需要注意的一点是:在默认情况下JsonResponse里面的内容必须是一个字典~如果我们想把一个列表通过JsonResponse方法返回给前端的话,需要设置一个参数就好了:
from django.http import JsonResponse
...
return JsonResponse([11,22,33],safe=False)
事实上,这种方式更受欢迎~因为前端工程师非常喜欢数组类型的数据,拿到后直接进行遍历就可以了~~好吧,还是看实际情况来讲把。
前端ajax传参给后台时需要注意的问题:
data参数中的键值对,如果值值不为字符串,需要将其转换成字符串类型:
$("#b1").on("click", function () { $.ajax({ url:"/ajax_add/", type:"GET", data:{"i1":$("#i1").val(),"i2":$("#i2").val(),"hehe": JSON.stringify([1, 2, 3])},//这里需要将数组序列化成JSON字符串 success:function (data) { $("#i3").val(data); } }) })
不能直接进行序列化数据类型的特殊处理
上面关于“json数据类型和python数据类型的对比”那张图显示了两种语言数据类型的对应关系。这也意味着不是所有的Python数据类型都可以进行序列化操作的!
实际中我见到不能直接序列化的Python数据类型是Decimal与Date跟Datetime数据类型。
其实,让它们可序列化的基本思路就是将这几种数据类型的数据转换成Python的str类型的数据:
Decimal数据类型的处理
现在遇到的Decimal数据类型的数据都是我从数据库中得到的,它是不可以直接进行序列化操作的,需要将其转换成str,再进行序列化操作:
这里的d一开始是Decimal类型的数据
import decimal d = str(decimal.Decimal(d).quantize(decimal.Decimal('0.00')))
Datetime与Date类型数据的处理
Python内置的datetime模块有strftime方法可以为我们将时间类型转换成字符串类型的数据:
这里的t一开始是datetime类型的数据
from datetime import datetime t = datetime.strftime(t,'%Y-%m-%d')
对于这两种类型的数据有位大佬写了一个类进行了统一处理,这里直接上大佬的代码:
import json from datetime import datetime from datetime import date #对含有日期格式数据的json数据进行转换 class JsonCustomEncoder(json.JSONEncoder): def default(self, field): if isinstance(field,datetime): return field.strftime('%Y-%m-%d %H:%M:%S') elif isinstance(field,date): return field.strftime('%Y-%m-%d') else: return json.JSONEncoder.default(self,field) d1 = datetime.now() dd = json.dumps(d1,cls=JsonCustomEncoder) print(dd)
关于datetime类型的数据的处理第一种方式我感觉比较常用,因为实际中我们要返回的字典不仅仅只有datetime还有其他类型的数据,需要用第一种方式去单独处理每个datetime数据;如果只有datetime类型的数据需要返回的化可以用第二种方式~