Django ajax使用

env: django ==1.11.9, python == 3.6.7

Ajax 在实际中是比较有用的,例如异步提交评论并渲染到页面,例如注册页面查寻输入的用户名是否已经存在,并提示给新注册的用户。

这里记录一个简单例子:

在不需要后台时我们只需要要通过js就能完成简单的计算:

<!DOCTYPE html>
{% load staticfiles %}
<html>
<body>
<p>请输入两个数字</p>
<form action="/add/" method="get">
    a: <input type="text" id="a" name="a"> <br>
    b: <input type="text" id="b" name="b"> <br>
    <p>result: <span id='result'></span></p>
    <button type="button" id='sum'>提交</button>
</form>

<script src="{% static 'js/jquery-3.3.1.min.js' %}"></script>
<script>
    $(document).ready(function () {
        {#$.ajax()#}
        $("#sum").click(function () {
            var a = $("#a").val();
            var b = $("#b").val();
            ret = parseInt(a) + parseInt(b);
            $('#result').html(ret);
        });
    });
</script>
</body>
</html>

当然的输入两个数字(实际获取的是两个字符串),并点击提交时,js将字符转换成int类型,然后相加,并在页面上显示。

那如果是需要提交到后台(这里并没有真的与数据库交互,而只是在views中处理,实际如果要与数据库交互只需要在此基础上添加即可。

我们通过get方法提交:

<script src="{% static 'js/jquery-3.3.1.min.js' %}"></script>
<script>
    $(document).ready(function () {
        $("#sum").click(function () {
            var a = $("#a").val();
            var b = $("#b").val();
            $.get(
                '{% url "show" %}',
                {'a': a, 'b': b},
                function (ret) {
                    $('#result').html(ret);
                },
            )
        });
    });
</script>
</body>

提交的请求是:"GET /show/?a=1&b=2 HTTP/1.1" 200 2

但更通用的写法是这样的:

<script src="{% static 'js/jquery-3.3.1.min.js' %}"></script>
<script>
    $(document).ready(function () {
        $("#sum").click(function () {
            var a = $("#a").val();
            var b = $("#b").val();
            $.ajax(
                {
                    url: "{% url 'show' %}",
                    method: 'GET',
                    data: {'a': a, 'b': b},
                    success: function (ret) {
                        $('#result').html(ret);
                    }
                }
            )
        });
    });
</script>

ajax中是一个字典, 包含以下信息: 

url: 要提交的url,

method: 提交的方法

data:要提交的数据

success: 回调函数, 成功后的动作,这里是将结果填到result中。还可以写failed

 

views.py

def show(request):
    if request.is_ajax():
        a = request.GET.get('a')
        b = request.GET.get('b')
        ret = int(a) + int(b)
        return HttpResponse(ret)
    else:
        return render(request, 'index.html')

request.is_ajax方法会判断是不是通过ajax提交过来的,然后就从GET中获取 数据,如果大量数据建议用POST(没有对数据量的限制),我们对数据进行处理后,返回结果,在index.html中也就success 后函数中接收到的ret.

总结:

之前关于ajax的使用每次都得重新查找之前写的例子,这里稍微总结一下:

方式一:直接指定提交的方法:$.get(), $.post(),默认情况下是get方式

此时是没有{}括号的,直接写url, data, callback即可。

方式二:$.ajax(), 此情况需要将所有内容写在{}中(字典)

主要内容包括: url, method, data, callback

个人更推荐方式二,程序易读性更强。

 

ajax的参数:

请求参数:

processData: 声明当前的data数据是否进行转码或者预处理,默认为true.当存在文件上传时,一定要设定为false,否则上传文件会失败,数据被处理后无法被后端处理。 如果processData被设置为false,{a:1,b:2}这样的数据为Json格式,会调用json对象的toString()方法,即{a:1,b:2}.toString(),得到一个{object, object}形式的结果。

如果你想传递字符串而非javascript对象,可以通过JSON.stringify({'a',1}),进行转换。

data: 当前ajax请求要携带的数据,是一个json的object对象,ajax方法就会默认地把它编码成某种格式(urlencoded:?a=1&b=2)

function testData() {
$.ajax("/test",{     //此时的data是一个json形式的对象
 data:{a:1,
 b:2
 }
});           

contenttype: 默认值为“application/x-www-urlencoded". 指定信息发送到服务器时内容编码类型,contentType:"application/json"发送json字符串,此时需要将数据通过JSON.stringify()转化然后再发送。

响应参数:

dataType: 预期服务器返回的数据类型,服务器返回的数据会根据这个值解析,传递给回调函数,默认情况下ajax会根据服务器返回的content Type来进行转换。如:return HttpResponse(ret_data_json,content_type='application/json') 这样设定后,ajax方法就会对响应的内容进行一个json格式的转换,如果转换成功,success回调函数会调用,而如果转换失败则触发error回调函数。

ajax 请求设置csrf_token

方式一:

jQuery(document).ajaxSend(function(event, xhr, settings) {
    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    function sameOrigin(url) {
        // url could be relative or scheme relative or absolute
        var host = document.location.host; // host + port
        var protocol = document.location.protocol;
        var sr_origin = '//' + host;
        var origin = protocol + sr_origin;
        // Allow absolute or scheme relative URLs to same origin
        return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
            (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
            // or any other URL that isn't scheme relative or absolute i.e relative.
            !(/^(\/\/|http:|https:).*/.test(url));
    }
    function safeMethod(method) {
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }

    if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
        xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
    }
});

这种方式在将它写在html文件中的<script>标签内或者写在独立文件内都行。

方式二:

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

这种方式只适合于写在html文件的<script>标签内。

方式三:

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

在django模板中{%csrf_token %}会被渲染成name='csrfmiddlewaretoken’隐藏标签,通过jquery获取 其什即可。

方式四:

<script src="{% static 'js/jquery.cookie.js' %}"></script>

$.ajax({

headers:{"X-CSRFToken":$.cookie('csrftoken')}, 

})

这种方法使用的前提是加载jquery.cookie.js,headers是ajax中的一个参数,

ajax 请求头

contentType指的是请求体的编码类型,常见的有三种:application/x-www-form-urlencoded, multipart/form-data,application/json

application/x-www-form-urlencoded,  浏览器的原生form表单post提交数据时如果不设置enctype属性,默认以此格式提交数据,ajax默认也是此格式。它会将数据拼接起来:a=1&b=2

 

multipart/form-data, 从名字看multipart表示分片发送数据,通常如果上传文件必须指定form表单的enctype类型为multipart/form-data,否则无法发送. 这种情况将文件分片发送后,在后台也应该进行分片写入,因为后台获取的是文件句柄对象,如果直接读写,可能存在文件过大导致问题,所以建议用 file_obj.chunks()方法. #chunks()默认一次返回大小为经测试为65536B,也就是64KB,最大为2.5M,是一个生成器

application/json, 表示序列化后的json字符串。当ajax中指定contentType为json时,data数据就不能是object类型,必须是json字符串。当前端使用这种方法传给后台时,django本身是没有处理方法的,所以需要自己导入json模块进行处理:

json.loads(request.body.decode("utf8")) .注意:此时,原始数据封闭在request.body中,但request.GET, request.POST中却是空的,所以不能用json.loads(request.POST.decode("utt8")). 

django 内置有序列化的方法,将queryset对象序列化为json字符串:

def books_json(request):
    book_list = models.Book.objects.all()[0:10]

    from django.core import serializers
    ret = serializers.serialize("json", book_list)

    return HttpResponse(ret)
 

或者在django中返回数据时直接使用Jsonresponse

from django.http import JsonResponse

def send_json(request):

    data = [{'name': 'Peter', 'email': '[email protected]'},
            {'name': 'Julia', 'email': '[email protected]'}]

    return JsonResponse(data, safe=False)

当数据类型不是字典类型,如上面是list类型,需要添加参数:safe=False

 

js中json数据的转换:

JSON.parse()用于将JSON字符串转换为js对象, 注意转换的json字符串中的引号必须相同,如:'{"name":"andy"}', 如果:'{name:"andy"}'会报错。

JSON.stringify(),用于将js对象转成JSON字符串

 

$.ajax({
            url:"{% url 'home' %}",
            type:'post',
            headers:{
                "X-CSRFToken":$.cookie('csrftoken'), 
                contentType:'json',
            },

            data:JSON.stringify({ 
                name:name,
            }),
            success:function (response) {

            }

        })

当你指定格式为json时,因为传给后台的是字符串,如果你把csrf_token放在字符串里面,而且后台没法直接解析,所以必定引发403forbidden。

所以此时必须将csrf_token写在header中,同样的道理:contentType也是header中的字段。

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)

 

上一篇:DateTimeField DateField 无法设置为editable

下一篇:Django 表单API