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)