• Django-Ajax


    一、Ajax基本用法

    1.简介

        AJAXAsynchronous Javascript And XML)翻译成中文就是异步的JavascriptXML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,现在更多使用json数据)。

        AJAX 不是新的编程语言,而是一种使用现有标准的新方法。

        AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。(这一特点给用户的感受是在不知不觉中完成请求和响应过程)

        AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。

          a.同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;

          b.异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。

       AJAX除了异步的特点外,还有一个就是:浏览器页面局部刷新;(这一特点给用户的感受是在不知不觉中完成请求和响应过程

    2.示例

    html页面内容:

    {% load static %}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    {% csrf_token %}
    
    用户名:<input type="text" id="i1" name="usename">
    <input type="button" value="提交" id="but">
    <span class="s1"></span>
    </body>
    <script src="{% static "jquery-3.4.1.js" %}"></script>
    <script>
    
        $("#but").click(function () {
            var name = $("#i1").val();
            var csrf_data = $('[name=csrfmiddlewaretoken]').val();
            $.ajax(
                {
                    url:"{% url 'login' %}",
                    type:"post",
                    data:{
                            name:name,
                            csrfmiddlewaretoken:csrf_data,
                        },
                    success:function (data) {
                        if (data==="123"){
                            alert("登陆成功")
                        }else {
                            $(".s1").text("用户名或密码错误!!!")
                        }
                    }
                }
            )
        })
    
    </script>
    
    </html>

    views内容:

    from django.shortcuts import render,HttpResponse,redirect
    
    # Create your views here.
    from app01 import models
    def index(request):
    
        return render(request,"index.html")
    
    def login(request):
        print(request.POST)
        data = request.POST.get("name")
        print(data)
        # <QueryDict: {'name': ['123'], 'csrfmiddlewaretoken': ['8lbAt5pr33TaApmK1I8UVUNgiY62uAp4qJoBjdH8oSt5XNe2eMd9XUd3daFKV8A9']}>
        return HttpResponse("123")

    urls内容:

    from django.conf.urls import url
    from app01 import views
    urlpatterns = [
        url(r'^index/', views.index,name="index"),
        url(r'^login/', views.login,name="login"),
    ]

    3.AJAX常见应用情景

        搜索引擎根据用户输入的关键字,自动提示检索关键字。

        还有一个很重要的应用场景就是注册时候的用户名的查重。

        其实这里就使用了AJAX技术!当文件框发生了输入变化时,使用AJAX技术向服务器发送一个请求,然后服务器会把查询到的结果响应给浏览器,最后再把后端返回的结果展示出来

          a.整个过程中页面没有刷新,只是刷新页面中的局部位置而已!

          b.当请求发出后,浏览器还可以进行其他操作,无需等待服务器的响应!

               

        当输入用户名后,把光标移动到其他表单项上时,浏览器会使用AJAX技术向服务器发出请求,服务器会查询名为lemontree7777777的用户是否存在,最终服务器返回true表示名为lemontree7777777的用户已经存在了,浏览器在得到结果后显示用户名已被注册!

        a.整个过程中页面没有刷新,只是局部刷新了;

        b.在请求发出后,浏览器不用等待服务器响应结果就可以进行其他操作;

    二、上传文件

    1、基于from表单上传文件

    URLS:

    from app01 import views
    urlpatterns = [
        url(r'^upload/', views.upload,name="upload"),
    ]

    HTML:

    {% load static %}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <form action="{% url "upload" %}" method="post" enctype="multipart/form-data">
        {% csrf_token %}
        用户名:<input type="text" name="username">
        头像:<input type="file" name="file">
        <input type="submit" value="提交" id="sub">
    </form>
    
    </body>
    <script src="{% static "jquery-3.4.1.js" %}"></script>
    
    </html>

    views:

    from django.shortcuts import render,HttpResponse,redirect
    
    # Create your views here.
    
    def upload(request):
        if request.method=="GET":
            return render(request,"upload.html")
        else:
            username = request.POST.get("username")  # 获取用户输入的内容
            file_obj = request.FILES.get("file")   # 获得文件数据对象
            print(username,file_obj.name)
            # 获取文件名字
            file_name = file_obj.name
            with open(file_name,"wb") as f:
                # for data in file_obj:   #读取数据
                #    f.write(data)     #每次读取的data不是固定长度的,和读取其他文件一样,每次读一行,识别符为
      
      
    ,遇到这几个符号就算是读了一行
    
    
                for data in file_obj.chunks():  #chunks()默认一次返回大小为经测试为65536B,也就是64KB,最大为2.5M,是一个生成器
                    f.write(data)
    
            return HttpResponse("ok")

    2、基于Ajax的文件上传

    HTML:

    {% load static %}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <div> <!--只是一个盒子,用不用都行-->
        {% csrf_token %}
        用户名:<input type="text" name="username">
        头像:<input type="file" name="file">
        <input type="button" value="提交" id="sub">
    </div>
    
    </body>
    <script src="{% static "jquery-3.4.1.js" %}"></script>
    
    <script>
    
        $("#sub").click(function () {
            // ajax上传文件的时候,需要这个类型,它会将添加给它的键值对加工成formdata的类型
            var formdata=new FormData();
            // 添加键值的方法是append,注意写法,键和值之间是逗号
            formdata.append("name",$("[type=text]").val());
            // 转换成DOM对象
            formdata.append("file",$("[type=file]")[0].files[0]);
    
            // 别忘了csrf_token
            formdata.append("csrfmiddlewaretoken",$("[name=csrfmiddlewaretoken]").val());
            $.ajax({
                    url:{% url "upload" %},
                    type:"post",
                    data:formdata,          // 将添加好数据的formdata放到data这里
                    processData: false ,    // 不处理数据
                    contentType: false,     // 不设置内容类型
                    success:function (response) {
                        console.log(response)
                    }
                }
            )
    
        })
    </script>
    
    </html>

    其他代码同上:

    注意:由于 FormData 是 XMLHttpRequest Level 2 新增的接口,现在 低于IE10 的IE浏览器不支持 FormData。

    三、请求头Content Type

    ContentType指的是请求体的编码类型,常见的类型共有3种:

    1、第一种请求方式:application/x-www-form-urlencoded

    这应该是最常见的 POST 提交数据的方式了。浏览器的原生 <form> 表单,如果不设置 enctype 属性,那么最终就会以 默认格式application/x-www-form-urlencoded 方式提交数据,ajax默认也是这个。请求类似于下面这样

    数据是以&符连接的:上面这种contenttype规定的数据格式,后端对应这个格式来解析获取数据,不管是get方法还是post方法,都是这样拼接数据,大家公认的一种数据格式,但是如果你contenttype指定的是urlencoded类型,但是post请求体里面的数据是下面那种json的格式,那么就出错了,服务端没法解开数据。

    2、第二种请求方式:multipart/form-data

    这又是一个常见的 POST 数据提交的方式。我们使用表单上传文件时,必须让 <form> 表单的 enctype 等于 multipart/form-data,form表单不支持发json类型的contenttype格式的数据,而ajax什么格式都可以发,也是ajax应用广泛的一个原因。直接来看一个请求示例:(了解)

    这个例子稍微复杂点。首先生成了一个 boundary 用于分割不同的字段,为了避免与正文内容重复,boundary 很长很复杂。然后 Content-Type 里指明了数据是以 multipart/form-data 来编码,本次请求的 boundary 是什么内容。消息主体里按照字段个数又分为多个结构类似的部分,每部分都是以 --boundary 开始,紧接着是内容描述信息,然后是回车,最后是字段具体内容(文本或二进制)。如果传输的是文件,还要包含文件名和文件类型信息。消息主体最后以 --boundary-- 标示结束。关于 multipart/form-data 的详细定义,请前往 rfc1867 查看。

          这种方式一般用来上传文件,各大服务端语言对它也有着良好的支持。

          上面提到的这两种 POST 数据的方式,都是浏览器原生支持的,而且现阶段标准中原生 <form> 表单也只支持这两种方式(通过 <form> 元素的 enctype 属性指定,默认为 application/x-www-form-urlencoded。其实 enctype 还支持 text/plain,不过用得非常少)。

          随着越来越多的 Web 站点,尤其是 WebApp,全部使用 Ajax 进行数据交互之后,我们完全可以定义新的数据提交方式,给开发带来更多便利。

    3、第三种请求方式:application/json

    客户端如果指定以json作为请求体的编码类型,那么服务端在接收后也要以对应的数据格式进行解码:
    Django不支持json格式的编码类型,若浏览器请求使用json这种编码类型发送请求的那么就需要我们自定义解析器,对数据进行解析:
    HTML代码:
    {% load static %}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <div>
    
        用户名:<input type="text" name="username">
        密码:<input type="password" name="password">
        <input type="button" value="提交" id="btn">
    </div>
    
    </body>
    
    <script src="{% static "jquery-3.4.1.js" %}"></script>
    
    <script>
        $("#btn").click(function () {
    
            $.ajax({
                url:{% url "index" %},
                type:"post",
                headers:{'Content-Type':'application/json'}, // 指定数据编码格式
                data:JSON.stringify({        // 对数据进行序列化
                    name:$("[name=usename]").val(),
                    pwd:$("[name=password]").val(),
                }),
    
                success:function (response) {
                    console.log(typeof response);    // python序列化后的json字符串
                    var dic = JSON.parse(response);  // 需要进行反序列化才可以用
                    console.log(dic.info)            // 直接可以调用对应的属性
                }
            })
        })
    
    </script>
    
    </html>

    视图函数:

    import json
    def index(request):
        if request.method=="GET":
            return render(request,"index.html")
    
        else:
            html_json = request.body         # 取出原数据,在对数据进行反序列化
            py_str = json.loads(html_json)   # 反序列化成字典,在处理
            print(py_str)   # {'pwd': '123'}
    
    
            res_dic = {"status":0,"info":"响应信息"}
            str_dic = json.dumps(res_dic)      # 将字典序列化成json字符串
            return HttpResponse(str_dic)        # 发送给ajax的response

    import json
    def index(request):
        if request.method=="GET":
            return render(request,"index.html")
    
        else:
            html_json = request.body          # 取出原数据,在对数据进行反序列化
            py_str = json.loads(html_json)   # 反序列化成字典,在处理
            print(py_str)                             # {'pwd': '123'}
    
            res_dic = {"status":0,"info":"响应信息"}
            str_dic = json.dumps(res_dic)
    
            # 指定数据编码格式相当于告诉浏览器按照这个格式进行解码
            return HttpResponse(str_dic,content_type="application/json")
    django指定数据格式
    {% load static %}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <div>
    
        用户名:<input type="text" name="username">
        密码:<input type="password" name="password">
        <input type="button" value="提交" id="btn">
    </div>
    
    </body>
    
    <script src="{% static "jquery-3.4.1.js" %}"></script>
    
    <script>
        $("#btn").click(function () {
    
            $.ajax({
                url:{% url "index" %},
                type:"post",
                headers:{'Content-Type':'application/json'}, // 指定数据编码格式
                data:JSON.stringify({        // 对数据进行序列化
                    name:$("[name=usename]").val(),
                    pwd:$("[name=password]").val(),
                }),
    
                success:function (response) {
                    console.log(response.info);      //拿到json数据类型的数据,根据服务器指定的数据编码格式调用内部的解析器进行解码
            })
        })
    
    </script>
    
    </html>
    HTML

    注意JsonResponse默认只处理字典类型的数据,如果想要返回其他数据类型:

    总结:

    form表单不支持json数据格式的传输
    django不支持json数据格式的解析,需要我们自定义解析器
    import json
    dic={"chao":"123"}
    
    dic_en = json.dumps(dic)
    print(dic_en,type(dic_en))
    
    
    aa = dic_en.encode("utf-8")
    print(aa)
    
    
    bb = json.loads(aa)
    print(bb,type(bb))
    
    """
    {"chao": "123"} <class 'str'>
    b'{"chao": "123"}'
    {'chao': '123'} <class 'dict'>
    """
    # bytes类型的字典,可以直接loads成字典,不需要decode

    四、序列化models对象:

    from django.urls import reverse
    book_objs = models.Book.objects.all().values('title','price')
    # django内部序列化方法
    res = serializers.serialize('json', book_objs)
    # 建议用下面这种方式序列化,强转数据类型
    books = list(book_objs)
    

    通过json序列化时间日期格式数据的时候需要注意,不能直接序列化:

    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)

    五、Ajax通过csrf_token的几种方式

    方式1

    通过获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送。

    $.ajax({
      url: "/cookie_ajax/",
      type: "POST",
      data: {
        "username": "chao",
        "password": 123456,
        "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val()  // 使用jQuery取出csrfmiddlewaretoken的值,拼接到data中
      },
      success: function (data) {
        console.log(data);
      }
    })

    方式2

    $.ajaxSetup({
        data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
    });

    方式3

    通过获取返回的cookie中的字符串 放置在请求头中发送。

    注意:需要引入一个jquery.cookie.js插件。

    <script src="{% static 'js/jquery.cookie.js' %}"></script>
    
    $.ajax({
     
    headers:{"X-CSRFToken":$.cookie('csrftoken')}, #其实在ajax里面还有一个参数是headers,自定制请求头,可以将csrf_token加在这里,我们发contenttype类型数据的时候,csrf_token就可以这样加
     
    })

    注意:如果我们发送的是json数据格式的数据,那么csrf_token就不能直接写在data里面了,没有效果,必须通过csrf的方式3的形式来写,写在hearders(请求头,可以写一些自定制的请求头)里面,注意,其实contentType也是headers里面的一部分,写在里面外面都可以:

    六、Ajax验证登录

    HTML:

    {% load static %}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    {% csrf_token %}
    
    用户名:<input type="text" id="i1" name="username">
    密码:<input type="text" id="i1" name="password">
    <input type="button" value="提交" id="but">
    <span class="s1"></span>
    </body>
    <script src="{% static "jquery-3.4.1.js" %}"></script>
    <script>
    
        $("#but").click(function () {
            var username = $("[name=username]").val();
            var password = $("[name=password]").val();
            var csrf_data = $('[name=csrfmiddlewaretoken]').val();
            $.ajax(
                {
                    url:"{% url 'login' %}",
                    type:"post",
                    data:{
                            name:username,
                            pwd:password,
                            csrfmiddlewaretoken:csrf_data,
                        },
                    success:function (data) {
                        if (data==="123"){
                            alert("登陆成功");
                            location.href="{% url "index" %}"
                        }else {
                            $(".s1").text("用户名或密码错误!!!")
                        }
                    }
                }
            )
        })
    
    </script>
    
    </html>
    View Code

    视图函数:

    from django.shortcuts import render,HttpResponse,redirect
    
    # Create your views here.
    from app01 import models
    
    def index(request):
        return render(request,"index.html")
    
    
    def login(request):
        if request.method=="GET":
            return render(request, "login.html")
        else:
            name = request.POST.get("name")
            pwd = request.POST.get("pwd")
            obj = models.Userinfo.objects.all()
            # 判断数据库的用户名和用户输入的的是否一致
            for info in obj:
                if name==info.username and pwd==info.password:
                    return HttpResponse("123")
            else:
                return render(request,"login.html")
    View Code

    URLS:

    from django.conf.urls import url
    from app01 import views
    urlpatterns = [
        url(r'^index/', views.index,name="index"),
        url(r'^login/', views.login,name="login"),
    ]
    View Code

    数据库用户信息表:

  • 相关阅读:
    Sql Server textcopy 的使用
    看来,我还是不适合犯罪
    Oracle 游标范例
    嵌入式学习方法 关于ARM+linux(转)
    存储控制器与外设之间的关系 (SDRAM与BANK6连接概述)
    socket和多线程可移植性编程基础(转)
    Linux设备驱动开发环境的搭建(转)
    Android JNI知识简介
    Linux USB驱动框架分析
    LINUX系统中动态链接库的创建和使用
  • 原文地址:https://www.cnblogs.com/songzhixue/p/10945358.html
Copyright © 2020-2023  润新知