Django中的Json知识拾遗

Posted pyspark

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

以上是关于Django中的Json知识拾遗的主要内容,如果未能解决你的问题,请参考以下文章

Django-组件拾遗

Java线程知识拾遗

java知识点拾遗:)

Python基础day03:入门知识拾遗

[C#.NET 拾遗补漏]02:数组的几个小知识

Flask拾遗笔记之上下文