ajax
stringify与parse方法
JavaScript中关于JSON对象和字符串转换的两个方法:
JSON.parse(): 用于将一个 JSON 字符串转换为 JavaScript 对象
JSON.parse('{"name":"alex"}');
JSON.parse('{name:"alex"}') ; // 错误
JSON.parse('[18,undefined]') ; // 错误
JSON.stringify(): 用于将 JavaScript 值转换为 JSON 字符串。
JSON.stringify({"name":"alex"})
python中数据类型的转化
1. python对象 ——》 json字符串
import json
json.dumps(python的数据类型)
2. json字符串 ——》python对象
json.loads(json字符串)
3.支持的数据类型 字符串 数字 布尔值 列表 字典 None
django在视图函数中发送json格式的数据
1,使用json模块 json.dumps() ,ajax还需要进行json解析
#views.py
return HttpResponse(json.dumps({"msg":"ok!"}))
#index.html
var data=json.parse(data)
console.log(data.msg);
2,使用 JsonResponse 可以发送字典,两边都不需要进行json的序列化与反序列化,ajax接受的直接是一个对象
#views.py
from django.http import JsonResponse
return JsonResponse({"msg":"ok!"})
#index.html
console.log(data.msg);
JsonResponse 对象:
class JsonResponse(data, encoder=DjangoJSONEncoder, safe=True, json_dumps_params=None,**kwargs)
这个类是HttpRespon的子类,它主要和父类的区别在于:
a).它的默认Content-Type 被设置为: application/json
b).第一个参数,data应该是一个字典类型,当 safe 这个参数被设置为:False ,那data可以填入任何能被转换为JSON格式的对象,比如list, tuple, set。 默认的safe 参数是 True. 如果你传入的data数据类型不是字典类型,那么它就会抛出 TypeError的异常。
c).json_dumps_params参数是一个字典,它将调用json.dumps()方法并将字典中的参数传入给该方法。
3,使用Django内置的serializers模块,可以发送queryset数据库对象
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)
ajax
AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。(这一特点给用户的感受是在不知不觉中完成请求和响应过程)
向服务端发请求的方法:
1. 在浏览器的地址栏上输入URL 回车 —— 》GET
2. 使用form表单 提交 —— 》 GET/POST
1. action # 提交的地址
2. method # 提交方式
3. 上传文件的时候 enctype="multipart/form-data"
4. input标签要有name属性
5. 要有一个type=sumbit的按钮或者input
3. a标签 —— 》GET
4. Ajax
使用ajax局部刷新页面例子,计算两个数相加之和 浏览器获取两个数,通过ajax发送到后端,后端相加后将结果返回给浏览器,浏览器的结果框局部刷新渲染这个结果
csrf验证是防止别的程序发post请求到我的网址,对于自己写的网页我们给每个访问网址的浏览器加上一个cookie,然后让我们的程序发post请求时也带一个cookie,当浏览器发请求时经过中间件 process_request获取浏览器带的cookie,然后process_view获取了post请求中的cookie,并和浏览器带的cookie进行比较,一致允许访问,不一致拒绝访问
在post表单中加{% csrf_token %} 可以给post中带cookie,并给浏览器中加cookie
给views中的函数加装饰器 @ensure_csrf_cookie ,也可以给浏览器加cookie, CBV的views只能把装饰器加到 dispatch() 方法上
# 不考虑csrf的ajax提交post请求(注掉中间件)
# urls.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/', views.index),
url(r'^calc/', views.calc),
]
# views.py
from django.shortcuts import render,HttpResponse
def index(request):
return render(request,'index.html')
def calc(request):
l1 = int(request.POST.get('i1'))
l2 = int(request.POST.get('i2'))
res = l1+l2
return HttpResponse(res)
# index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>ajex提交</h2>
<input type="text" id="i1">+
<input type="text" id="i2">=
<input type="text" id="i3">
<button type="submit" id="b1">计算</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
$('#b1').click(function () {
var i1=$('#i1').val();
var i2=$('#i2').val();
$.ajax({
url:'/calc/', # 请求地址是 /calc/
type:'post',
data:{
'i1':i1,
'i2':i2
},
success:function (res) { # res是 calc函数的返回值,calc返回的是相加后的结果,这里接收
console.log(res);
$('#i3').val(res);
}
})
})
</script>
</body>
</html>
# 考虑csrf的情况,需要给ajax的post请求加上cookie
方法一:通过获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送。
# index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>ajex提交</h2>
{% csrf_token %}
<input type="text" id="i1">+
<input type="text" id="i2">=
<input type="text" id="i3">
<button type="submit" id="b1">计算</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
$('#b1').click(function () {
var i1=$('#i1').val();
var i2=$('#i2').val();
$.ajax({
url:'/calc/',
type:'post',
data:{
'i1':i1,
'i2':i2,
"csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val() // 使用jQuery取出csrfmiddlewaretoken的值,拼接到data中
},
success:function (res) {
console.log(res);
$('#i3').val(res);
}
})
})
</script>
</body>
</html>
方法二:通过获取返回的cookie中的字符串 放置在请求头中发送
...
{% csrf_token %}
...
$.ajax({
url:'/calc/',
type:'post',
headers:{"X-CSRFToken":$.cookie('csrftoken')}, //从Cookie取csrftoken,并设置到请求头中
data:{
'i1':i1,
'i2':i2,
},
success:function (res) {
console.log(res);
$('#i3').val(res);
}
})
...
方法三:自己写一个getCookie的js文件
因为是js文件需要放到静态文件中,所以把以下代码写在static目录下,然后命名为ajax_setup.js ,然后在index.html页面链接js <script src="/static/ajax_setup.js"></script>
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;
}
var csrftoken = getCookie('csrftoken');
// 每一次都这么写太麻烦了,可以使用$.ajaxSetup()方法为ajax请求统一设置
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
如果使用从cookie中取csrftoken的方式,需要确保cookie存在csrftoken值。
如果你的视图渲染的HTML文件中没有包含 {% csrf_token %},Django可能不会设置CSRFtoken的cookie。
这个时候需要使用ensure_csrf_cookie()装饰器强制设置Cookie。
推荐在 views 函数里加装饰器,然后在模板中就不用写 {% csrf_token %} 了
django.views.decorators.csrf import ensure_csrf_cookie
@ensure_csrf_cookie
def login(request):
pass
# 上传文件
# urls.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^ajax_file/', views.ajax_file),
url(r'^form_file/', views.form_file),
]
# views.py
def form_file(request):
if request.method == 'POST':
file_obj = request.FILES.get('file')
with open(file_obj.name,'wb') as f:
for i in file_obj.chunks(): # 使用chunks()函数可以一点一点上传
f.write(i)
return HttpResponse('上传成功')
return render(request,'form_file.html')
def ajax_file(request):
file_obj = request.FILES.get('f1')
with open(file_obj.name,'wb') as f:
for i in file_obj.chunks():
f.write(i)
return HttpResponse('上传成功')
# form_file.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
</head>
<body>
{#-------------------使用form表单上传文件-----------------#}
<form action="" method="post" enctype="multipart/form-data"> # 需要指定enctype = 'multipart/form-data',不然默认的是下面的,会把我们上传的文件以键值对的形式(和url类似)拼接,然后放到请求体中
{#<form action="" method="post" enctype="application/x-www-form-urlencoded">#}
{% csrf_token %}
<input type="file" name="file">
<button>上传</button>
</form>
<hr>
{#--------------------使用ajax上传文件--------------------------#}
<h2>ajax上传文件</h2>
<input type="file" name="file" id="f1">
<button id="b1">上传</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
$("#b1").click(function () {
var formData = new FormData();
formData.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val());
formData.append("f1", $("#f1")[0].files[0]); {# $("#f1")[0] 把jquery对象变为js对象#}
$.ajax({
url: "/ajax_file/", {# 转向ajax_file路径,向这个路径发送请求 #}
type: "POST",
processData: false, // 告诉jQuery不要去处理发送的数据
contentType: false, // 告诉jQuery不要去设置Content-Type请求头
data: formData,
success: function (data) {
console.log(data)
}
})
})
</script>
</body>
</html>
# 使用json发送字符串
def ajax_test(request):
print(request.POST)
print(request.POST.get('name'))
print(request.POST.get('hobby'),type(request.POST.get('hobby')))
d = {'status':0,'msg':''}
# return HttpResponse(json.dumps(d))
return JsonResponse(d) # JsonResponse直接以json格式发送字典
# 用户名注册,从数据库匹配用户名是否存在,如果存在提示,不存在注册
# 用户名注册,从数据库匹配用户名是否存在,如果存在提示,不存在注册
# views.py
def reg(request):
ret = {'status': 0, 'msg': ''}
if request.is_ajax():
name = request.POST.get('username')
is_exist = models.UserInfo.objects.filter(username=name)
if is_exist:
ret['msg'] = '用户名已存在'
ret['status'] = 1
else:
ret['msg'] = '用户名可以使用'
return JsonResponse(ret)
return render(request, 'reg.html')
# reg.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
</head>
<body>
<input type="text" id="i1"><span style="color: red"></span>
<button id="b1">点击</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script src="/static/ajax_setup.js"></script>
<script>
$("#i1").blur(function () { <!-- i1失焦时,发送ajax请求-->
var _this = $(this);
$.ajax({
url: '/reg/',
type: 'post',
data: {'username': $("#i1").val()},
success: function (res) {
console.log(res);
if (res.status != 0) {
_this.next().text(res.msg); <!--next指的是下一个标签-->
}
}
})
});
$("#i1").focus(function () { <!-- i1聚焦时,清空span标签的内容-->
$(this).next().text('') <!-- input标签改变文本内容使用 .val(文本内容) span标签改变文本内容 .text(文本内容)-->
})
</script>
</body>
</html>
# 使用ajax的方式删除班级对象,当点击删除按钮时,通过ajex把班级对象的id传给后端,然后后端在数据库中删除这个班级对象,将成功的结果返回给ajax,然后前端删除该班级标签
# 使用ajax的方式删除每个班级对象
# html文件
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>序号</th>
<th>ID</th>
<th>班级</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for class in class_list %}
<tr data_id={{ class.id }}>
<td>{{ forloop.counter }}</td>
<td>{{ class.id }}</td>
<td>{{ class.name }}</td>
<td>
<span class="btn btn-danger btn-sm ">
<i class="fa fa-trash-o fa-fw"></i>删除
</span>
<a class="btn btn-success btn-sm" href="/edit_class/?id={{ class.id }}">
<i class="fa fa-edit fa-fw"></i>编辑
</a>
</td>
</tr>
{% empty %}
<tr>
<td colspan="4" style="text-align: center">没有数据</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!--使用sweetalert插件,可以显示弹窗-->
<script src="/static/plugins/dist/sweetalert.min.js"></script>
<link rel="stylesheet" href="/static/plugins/dist/sweetalert.css">
<!--jquery也用的到-->
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
$(".btn-danger").on("click", function (event) {
_this = $(this);
swal({
title: "你确定要删除吗?",
text: "删除可就找不回来了哦!",
type: "warning",
showCancelButton: true,
confirmButtonClass: "btn-danger",
confirmButtonText: "删除",
cancelButtonText: "取消",
closeOnConfirm: false
},
function () {
{#var deleteId = _this.parent().parent().attr('data_id'); 测试用#}
$.ajax({
url: "/del_class/",
type: "post",
data: {"id": deleteId},
success: function (data) {
if (data.status === 1) {
console.log(deleteId);
console.log($(this), 'ajax中的this');
{#<!--#}
{#w.fn.init [{…}]#}
{#0:{url: "/del_class/", type: "POST", isLocal: false, global: true, processData: true, …}#}
{#length:1#}
{#__proto__:Object(0)#}
{#ajax中的$(this)是ajax对象,包含了ajax中的参数;ajax外的$(this)才是我们选中的span对象(删除按钮)#}
{#-->#}
console.log(_this, 'ajax外的this');
{#<!--#}
{#w.fn.init [span.btn.btn-danger.btn-sm]#}
{#0:span.btn.btn-danger.btn-sm#}
{#length:1#}
{#__proto__:Object(0)-->#}
_this.parent().parent().remove()
{#$("[data_id=deleteId]").remove(); 测试用#}
{#不知道为什么这样用属性选择器不能找到,不是属性选择器的问题,是deleteId的问题,因为把deleteId换成一个具体的数字就行了,可能是属性选择器后面的属性不能用变量,因为我发现放数字和放变量data_id在pycharm上的颜色不同#}
swal("删除成功!", "你可以准备跑路了!", "success");
} else {
swal("删除失败", "你可以再尝试一下!", "error")
}
},
});
});
})
</script>
# views 中del_class函数
def del_class(request):
del_class = request.POST.get('id')
class_obj = models.Class.objects.get(id=del_class)
class_obj.delete()
data = {}
data['status'] = 1
return JsonResponse(data)
浙公网安备 33010602011771号