Django中的Json知识拾遗

    在做Django项目时,用到了很多AJax的知识,说到Ajax就会涉及到json的知识,因此索性准备来一篇博客,将项目过程中遇到的问题记录下,以方便日后的查阅。

一.什么是JSon?

JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。
它基于 ECMAScript (w3c制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。
简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

说到这里大家可能还是难以理解,说白了,json就是一种通用的数据交换格式,有了json,我们就可以在不同语言之间交互数据,能够非常方便我们的操作,我们来看这样一个需求:Python负责爬取数据,Java用来做大数据分析:

例如:Python负责爬取数据,这些数据构成了一个大的字典,现在需要给Java处理!如果直接发送给Java处理,Java肯定处理不了,那是因为你Python中的字典,我Java压根不认识,因为你们的语法不一样,所以我处理不了!但是现在我就要处理这些数据,现在就需要一套标准,这套标准就是用来定义Python和Java之间的数据交换协议——例如这里的Json,我将Python的字典序列化成json格式的字符串,然后你Java拿到后再使用json进行反序列化成你认识的对象,这样我们就完成了不同语言之间的数据交换

再例如,我们使用Python做Web开发,经常需要和前端JS交互数据,此时又会用到json,例如将Python生成的字典序列化成如下json的字符串传递给前端,前端在使用json反序列化成JS能够识别的字符串即可。

大家要记住:

无论什么语言,序列化成的JSON格式都一样的,都是JSON字符串!但是反序列化后,分情况:使用js来反序列化json字符串得到的就是js支持的基本数据类型,使用java反序列化json字符串得到的就是java支持的基本数据类型,使用python反序列化也是同样的道理。

另外大家还要注意一点:JSON来源于JS中的数据类型,它只是取出了双引号的object类型(类似于字典),事实上json对象可以从JS对象中拿出一些标准,也可以从Java中拿,不论怎么拿,这套标准都是一样的。明白了上面所说的这些,我们来看下面这张图就清楚明了多了:

从上图中可以看到,Python中的基本数据类型和json中的基本数据类型存在一系列对应关系,例如Python中的字典对象对应到json中object类型,也就是说但凡是支持json数据格式的语言,其基本数据类型都和json有对应关系,有了这层对应关系,就可以直接使用json进行序列化,这也就是为什么我们在之前的Django项目中使用可以使用JSonresponse直接序列化一个字典对象的原因,并且前端可以不用反序列化就可以使用的原因,因为Python中的字典和json中object对象类型对应,所以不需要使用json.dumps先序列化成字符串,然后再返回给前端。

笔者曾经遇到过一个大坑:日期类型的序列化

我们每次对文章评论完毕后,都会显示评论时间,这个评论时间就是最终的入库时间,既然要在前端进行展示,我们需要将时间取出来然后传递回去,但问题在于我们在定义数据模型的时候,时间是一个DateTimeField的字段类型,JSon是无法序列化一个datetime.datetime的日期对象的,因为没有一个对应的关系,也就是说我们不能直接使用JsonResponse来进行序列化,要不然会报错:

前面我们说过,既然无法直接序列化,我就使用python中的json.dumps来先将你序列化成字符串,然后再传递给前端即可,这也就是我们为什么在comment视图中使用HttpResponse来传递后端数据,而不使用JsonResponse来序列化数据的原因,来看代码即可:

def comment(request):
    """
    服务端需要客户端传递过来三个数据:
    1.评论内容,2.评论的文章,3.当前评论的根评论的ID:parent_comment_id
    由于只有登入的用户可以评论,所以当前的用户ID就是登入用户的ID
    如果当前评论存在根评论,那说明这次提交的是子评论,否则提交的就是根评论
    """
    comment_content = request.POST.get("content")
    article_id = request.POST.get("article_id")
    parent_comment_id = request.POST.get("parent_comment_id")
    user_id = request.user.nid
    """
    注意最终渲染到页面上的时间,是该条评论的入库时间,而不是该条评论的提交时间;
    """
    comment_response = {}
    if parent_comment_id:  # 提交的是子评论,构建评论树
        """
        如果提交的是子评论,那么同样需要往comment表中插入一条记录,同时要
        往文章表中的评论数+1,这里又是一个事务操作,这里使用create方法往评论表中插入一条数据的时候会得到一个
        评论对象current_comment
        """
        with transaction.atomic():
            current_comment = Comment.objects.create(content=comment_content, user_id=user_id, article_id=article_id,
                                                     parent_comment_id=parent_comment_id)
            Article.objects.filter(article_id=article_id).update(comment_count=F("comment_count") + 1)
            comment_response["parent_comment_content"] = current_comment.parent_comment.content
            comment_response["parent_comment_user"] = current_comment.parent_comment.user.username
    else:  # 提交的就是根评论
        """
        将根评论内容添加至comment表中
        然后将文章表中的评论数comment_count自加1
        """
        with transaction.atomic():
            current_comment = Comment.objects.create(content=comment_content, user_id=user_id, article_id=article_id)
            Article.objects.filter(article_id=article_id).update(comment_count=F("comment_count") + 1)
        # 给前端ajax返回相应的数据进行渲染
        """
        这里有2点需要注意:
        1.如果直接通过current_comment.comment_date获取当前记录的入库时间,此时该时间是一个datetime对象
        如果直接使用进行序列化会报错。
        """
    comment_response["content"] = current_comment.content
    comment_response["comment_date"] = current_comment.comment_date.strftime("%Y-%m-%d %H:%m")
    comment_response["comment_id"] = current_comment.nid
    return HttpResponse(json.dumps(comment_response))

在上面的思路中,我们自己处理,借助于datetime模块的strfttime完成对日期对象的处理,然后使用json.dumps来序列化最终的字符串对象,如下所示:

comment_response["comment_date"] = current_comment.comment_date.strftime("%Y-%m-%d %H:%m")
print(type(comment_response["comment_date"])) 此时它是一个普通的Python字符串对象

笔者继续给大家举一个实际例子:我们之前使用Ajax将编辑后的老师信息发送给后端数据库进行修改,看如下的代码:

$(document).ready(function () {
    //给table表里面的所有modal编辑按钮绑定事件,使用Jquery的事件委派
    $("table").on("click", ".m-edit", function () {
        //一旦点击modal编辑讲师按钮,即可弹出模态框,myEditModal为模态框的唯一ID
        $("#myEditModal").modal("show");
        //此时模态框中已经有值存在了,这是通过Ajax发出的get请求获取的值,要不然我们是无法重新编辑值的,接下来我们取值
        var $tds = $(this).parent().parent().children(); // 获取表格中所有的td标签
        var teacherID = $($tds[0]).text();
        var teacherName = $($tds[1]).text();
        var teacherGender = $($tds[2]).text();
        var teacherSalary = $($tds[3]).text();
        //使用Ajax获取老师任教的班级,因为teacherID和teacherName在请求teacher_list时,就可以获取到
        //但是老师的班级是个列表怎么获取,我们这里使用Ajax来获取
        $.ajax({
            url: "/modal_teacher_list/?teacher_id="+teacherID,
            type: "GET",
            success: function (data) {
                console.log(data);
                var classIDs = JSON.parse(data);
                // 获取当前老师所带班级的ID
                $("#editTeacherSelect").val(classIDs);
            }
        });
        //然后来填充模态框中各个字段的值
        $("#editTeacherName").val(teacherName);
        $("#editTeacherGender").val(teacherGender);
        $("#editTeacherSalary").val(teacherSalary);
        $("#editTeacherID").val(teacherID);
    });

    // 给编辑老师信息模态框的提交按钮绑定事件
    $("#edit-modal-submit").on("click", function () {
        //获取编辑之后的值
        var teacherID = $("#editTeacherID").val();
        var teacherName = $("#editTeacherName").val();
        var teacherGender = $("#editTeacherGender").val();
        var teacherSalary = $("#editTeacherSalary").val();
        // 获取编辑后老师所带的班级ID,一个老师带多个班级,所以这里得到的是一个数组,思考后面怎么将数组传递到后台
        var classIDs = $("#editTeacherSelect").val();

        //使用Ajax提交到后端
        $.ajax({
            url: "/modal_edit_teacher/",
            type: "post",
            //注意使用Ajax提交数组到前端时,需要使用JSON.stringify()序列化为字符串
            data: {"teacher_id": teacherID, "teacher_name":teacherName, "teacher_gender": teacherGender,
                    "teacher_salary": teacherSalary, "class_ids": JSON.stringify(classIDs)},
            success: function (data) {
                //从前端接接收到的为json字符串,需要反序列化为js对象
                var dataObj = JSON.parse(data);
                if (dataObj.status === 0){
                    location.reload()
                }else{
                    //如果更新失败,那就隐藏模态框,同时弹出swall效果
                    $("#myEditModal").modal("hide");
                    swal("我擦", "更新失败了", "error");
                }
            }
        })
    })
});

在上面的需求中,一个老师可以带领多个班级,这里的班级在JS中是一个数组,我们不可能直接将数组放在Ajax中的data中进行传递,因此需要使用JS的序列化方法,将其序列为一个字符串对象,然后再进行传递,如下:

data: {"teacher_id": teacherID, "teacher_name":teacherName, "teacher_gender": teacherGender,"teacher_salary": teacherSalary, "class_ids": JSON.stringify(classIDs)}

后台在收到序列化后的班级列表字符串后,肯定需要使用Python来反序列化为Python中的列表对象:

teacher_class_ids = request.POST.get("class_ids")
teacher_ids = json.loads(teacher_class_ids)

二.正确认识JSon格式

笔者在做项目的过程中经常将JSON对象,JSON字符串以及两者之间互转弄混淆,基于此,笔者在此整理一下,方便日后查阅:

【001】Json对象:是指符合json格式要求的js对象,前面笔者提到过json就是来源于JS;既然是对象,那就可以使用对象名.属性名来调用,看如下的例子:

 var person={"name":"zhangsan","sex":"男","age":"24"}; //json对象
 alert(person.name);//zhangsan
 alert(typeof person);//object

person就是json对象。可以用perosn.name这种方式进行属性的调用。第三行代码就是看person的类型,为object类型;注意json对象中的属性名必须要是双引号,例如下面这样的格式是不对的:

{ name: "张三", ‘age‘: 32 }                     // 属性名必须使用双引号

[32, 64, 128, 0xFFF] // 不能使用十六进制值

{ "name": "张三", "age": undefined }            // 不能使用undefined

{ "name": "张三",
  "birthday": new Date(‘Fri, 26 Aug 2011 07:13:10 GMT‘),
  "getName":  function() {return this.name;}    // 不能使用函数和日期对象
}  

【002】字符串,我们常说的JavaScript中的字符串是单引号或者双引号引起来的,而Json字符串指的是符合json格式要求的js字符串,如下:

var person=‘{"name":"zhangsan","sex":"男","age":"24"}‘;//json字符串
alert(person);//{"name":"zhangsan","sex":"男","age":"24"}
alert(typeof person);//string

person就是一个json字符串,之所以叫json字符串,因为字符串的格式符合json的格式,第三行代码也匹配其中的类型为string。

【003】JSON字符串和JOSN对象的转换

json字符串转json对象,调用parse方法:

var person=‘{"name":"zhangsan","sex":"男","age":"24"}‘;//json字符串
var personObject = JSON.parse(person);
alert(personObject.name);//zhangsan

json对象转为json字符串,调用stringify方法:

var person={"name":"zhangsan","sex":"男","age":"24"};//json对象
var personString = JSON.stringify(person);
alert(personString);

关于Django中Ajax的使用我们将在下节中详细说明,希望各位好好掌握本篇博客的知识!

【004】stringify与parse方法

JSON.parse():     用于将一个 JSON 字符串转换为 JavaScript 对象 
eg:
console.log(JSON.parse(‘{"name":"Yuan"}‘));
console.log(JSON.parse(‘{name:"Yuan"}‘)) ;   // 错误
console.log(JSON.parse(‘[12,undefined]‘)) ;   // 错误

JSON.stringify(): 用于将 JavaScript 值转换为 JSON 字符串。 
eg:  console.log(JSON.stringify({‘name‘:"egon"})) ; 

【005】 最后给各位推荐一个可以格式化JSon字符串的在线网址,非常方便:https://www.bejson.com/

参考网址:https://www.cnblogs.com/gyx19930120/p/4419971.html

http://blog.csdn.net/android_xue/article/details/69488793

原文地址:https://www.cnblogs.com/pyspark/p/8166737.html

时间: 2024-10-07 03:03:47

Django中的Json知识拾遗的相关文章

[python]学习Django中的python知识拾遗

1.使用正则表达式进行URL匹配 urlpatterns = patterns('', # ... (r'^time/plus/\d+/$', hours_ahead), # ... ) (1)使用r代表字符串是原始字符串,表示python不会对立面的反斜杠\转义符进行处理,使用正则表达式一般使用原始字符串. (2)使用\d+表示匹配1个或者多个数字,如果限定只能使用两个数字,则\d{1,2}. (3)如果要把正则表达式的某个数作为参数,则用小括号包起来,如(r'^time/plus/(\d{1

Django中使用Json返回数据

在一个网站在,大量数据与前端交互,JSON是最好的传递数据方式了. 在Django中,使用JSON传输数据,有两种方式,一种是使用Python的JSON包,一种是使用Django的JsonResponse 方法一:使用Python的JSON包 1 from django.shortcuts import HttpResponse 2 3 import json 4 5 6 def testjson(request): 7 data={ 8 'patient_name': '张三', 9 'age

django中使用json.dumps处理数据时,在前台遇到字符转义的问题

django后台代码: import json ctx['dormitory_list'] = json.dumps([{"number": "111", "is_checked": 1}, {"number": "122", "is_checked": 0}, {"number": "133", "is_checked": 1

Django中的Ajax详解

AJAX(Asynchronous Javascript And XML)翻译成中文就是"异步Javascript和XML".即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML). 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求:异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求.AJAX除了异步的特点外,还有一个就是:浏览器页面局部刷新:(这一特点给用户的感受是在不知不觉中完成请

django中的CBV

CBV介绍 我们在写一个django项目时,通常使用的都是FBV(function base views) 而CBV(class base views)也有它自己的应用场景,比如在写一个按照rest规范写接口时,CBV的适用性就比FBV更强 先来看看CBV在django中的写法,与FBV有什么不同的地方 url(r'^students/', views.StudentsView.as_view()) 路由 from django.views import View class StudentsV

计算机底层知识拾遗(三)理解磁盘的机制

磁盘是一种重要的存储器,位于主存结构的下方,是永久存储的介质.在计算机底层知识拾遗(一)理解虚拟内存机制 这篇中说了虚拟内存是面向磁盘的,理解磁盘的工作原理对理解计算机的很多概念有很大的帮助.尤其是在数据库和分布式存储领域,要经常和磁盘打交道. 磁盘这块主要有几个部分的概念: 1. 磁盘的基本结构和工作原理 2. 如何在虚拟内存机制下与内存高效地交换数据 3. 磁盘如何保证数据存储的可靠性及故障恢复 磁盘的基本结构和工作原理 从单个磁盘来说,由一个个的同心圆组成,一个同心圆就是一个磁道,每个磁道

有关javascript中的JSON.parse和JSON.stringify的使用一二

有没有想过,当我们的大后台只是扮演一个数据库的角色,json在前后台的数据交换中扮演极其重要的角色时,作为依托node的前端开发,其实相当多的时间都是在处理数据,准确地说就是在处理逻辑和数据(这周实习最大的收获). 而对于依托json格式传输的数据,处理数据时,用到JSON.strinify和JSON.parse的概率是百分之百.使用这两个方法so easy,但是你真的知道其中一些相关的细节以及其中牵涉到的javascript的知识么? JSON.parse用于从一个字符串中解析出json对象.

c++基础知识拾遗

------------------<c++基础知识拾遗之&>--------------------------------- 在C里面,&有几种意思 1.当两个连在一起的时候.&&.代表的是"并且"的意思 例如a==1&&b==2.就是当a=1并且b=2的时候! 2.表示引用,例如int a; int &ra=a; //定义引用ra,它是变量a的引用,即别名 3.&表示两种运算符,其中一种表示取值运算符,一

Java线程知识拾遗

知识回顾 进程与线程是常常被提到的两个概念.进程拥有独立的代码段.数据空间,线程共享代码段和数据空间,但有独立的栈空间.线程是操作系统调度的最小单位,通常一个进程会包含一个或多个线程.多线程和多进程都可以实现并发处理,如 nginx 使用多进程方式.tomcat 使用多线程方式.Apache 支持混合使用.在 C/C++ 等语言中可以同时使用多进程和多线程,而在 Java 中只能使用多线程. 在 Java 中,创建线程的唯一方式是创建 Thread 类的实例,调用实例的 start() 方法启动