python项目Django(AJAX)
一 、Ajax简介
1.1 简介:
AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,现在更多使用json数据)。
AJAX 不是新的编程语言,而是一种使用现有标准的新方法。
AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。(这一特点给用户的感受是在不知不觉中完成请求和响应过程)
AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。
a.同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
b.异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
AJAX除了异步的特点外,还有一个就是:浏览器页面局部刷新;(这一特点给用户的感受是在不知不觉中完成请求和响应过程)
基于ajax简单示例:
页面输入两个整数,通过AJAX传输到后端计算出结果并返回。 html文件名称为ajax_demo1.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>AJAX局部刷新实例</title> </head> <body> <input type="text" id="i1">+ <input type="text" id="i2">= <input type="text" id="i3"> <input type="button" value="AJAX提交" id="b1"> <script src="/static/jquery-3.2.1.min.js"></script> <script> $("#b1").on("click", function () { $.ajax({ url:"/ajax_add/", //别忘了加双引号 type:"get", data:{"i1":$("#i1").val(),"i2":$("#i2").val()}, //object类型,键值形式的,可以不给键加引号 success:function (data) { $("#i3").val(data); } }) }) </script> </body> </html> views.py里面的内容: def ajax_demo1(request): return render(request, "ajax_demo1.html") def ajax_add(request): #time.sleep(10) #不影响页面发送其他的请求 i1 = int(request.GET.get("i1")) i2 = int(request.GET.get("i2")) ret = i1 + i2 return JsonResponse(ret, safe=False) #return render(request,'index.html') #返回一个页面没有意义,就是一堆的字符串,拿到了这个页面,你怎么处理,你要做什么事情,根本就没有意义 urls.py里面的内容: urlpatterns = [ ... url(r'^ajax_add/', views.ajax_add), url(r'^ajax_demo1/', views.ajax_demo1), ... ] 启动django项目,然后运行看看效果,页面不刷新,只是刷新页面中的局部位置而已!
1.2 AJAX常见应用情景:
搜索引擎根据用户输入的关键字,自动提示检索关键字。
还有一个很重要的应用场景就是注册时候的用户名的查重。
其实这里就使用了AJAX技术!当文件框发生了输入变化时,使用AJAX技术向服务器发送一个请求,然后服务器会把查询到的结果响应给浏览器,最后再把后端返回的结果展示出来。
a.整个过程中页面没有刷新,只是刷新页面中的局部位置而已!
b.当请求发出后,浏览器还可以进行其他操作,无需等待服务器的响应!
1.3 AJAX的优缺点:
get,post方法都能向后台提交数据
优点:
1.AJAX使用JavaScript技术向服务器发送异步请求;
2.AJAX请求无须刷新整个页面;
3.因为服务器响应内容不再是整个页面,而是页面中的部分内容,所以AJAX性能高;
注意:
1、如果你想通过ajax来删除表格中某条记录,并且ajax里面的url不写死的情况下(url反向解析),那么就需要下面这种方式,实现url里面参数的动态:
2、ajax里面写$(this)时要注意的问题:还有一点注意,如果你添加某些dom对象的时候,如果你想在不刷新页面的情况下来添加这个对象,那么你要注意,如果这个对象也需要绑定事件的话,你需要用on来给和他相同的标签对象来绑定事件。
3. 网页AJAX加载的选项,F12打开开发者选项,network下面的XHR的ajax加载的文件位置
1.4 AJAX的POST请求实例(基于用户登录验证):
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> 用户名:<input type="text" id="username"> 密码:<input type="text" id="pwd"> {% csrf_token %} <button id="sub">提交</button> <span style="color: red;font-size: 12px;" id="error"></span> </div> <script src="{% static 'jquery.js' %}"></script> <script> $('#sub').click(function () { $.ajax({ url:"{% url 'login' %}", type:'post', data:{username:$('#username').val(),pwd:$('#pwd').val(),csrfmiddlewaretoken:$('[name=csrfmiddlewaretoken]').val()}, success:function (data) { data = JSON.parse(data); console.log(data,typeof data); if (data['status']){ location.href=data['home_url']; } else { $('#error').text('用户名或者密码错误!') } } }) }) </script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1> 欢迎来到xxx官网 </h1> </body> </html>
url(r'^login/', views.login,name='login'), url(r'^home/', views.home,name='home'),
def login(request): res_dict = {'status':None,'home_url':None} if request.method == 'GET': return render(request,'login.html') else: uname = request.POST.get('username') pwd = request.POST.get('pwd') user_obj = models.UserInfo.objects.filter(name=uname,password=pwd).exists() import json if user_obj: res_dict['status'] = True res_dict['home_url'] = reverse('home') res_json_dict = json.dumps(res_dict) return HttpResponse(res_json_dict) #直接回复字典格式是不可以的,必须转换成json字符串,转换成普通字符串也是不行的,因为前端需要对json进行反序列获得这个字典,在通过字典的形式来操作数据。 else: res_dict['status'] = False res_json_dict = json.dumps(res_dict) return HttpResponse(res_json_dict) # 如果你就是不使用JsonResponse的话,也可以给HttpResponse添加一个参数,content_type='application/json',那么前端ajax拿到数据之后,也是不需要反序列化的,ajax的回调函数就收到的就是一个反序列化之后的一个对象,因为ajax接受到数据后,通过这个data_type或者content_type发现你发送来的是个json格式的数据,那么ajax内容就自动将这个数据反序列化得到了js的数据对象,然后通过对象可以直接操作数据。 # return HttpResponse(res_json_dict,data_type='application/json') # return JsonResponse(res_dict) def home(request): return render(request,'base.html')
二、Ajax的使用
1.基于jQuery的实现: <button class="send_Ajax">send_Ajax</button> <script> $(".send_Ajax").click(function(){ $.ajax({ url:"/handle_Ajax/", type:"POST", data:{username:"chao",password:123}, success:function(data){ console.log(data) }, error: function (jqXHR, textStatus, err) { console.log(arguments); }, complete: function (jqXHR, textStatus) { console.log(textStatus); }, statusCode: { '403': function (jqXHR, textStatus, err) { console.log(arguments); }, '400': function (jqXHR, textStatus, err) { console.log(arguments); } } }) }) </script>
2.基于原生js实现: var b2 = document.getElementById("b2"); b2.onclick = function () { // 原生JS var xmlHttp = new XMLHttpRequest(); xmlHttp.open("POST", "/ajax_test/", true); xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xmlHttp.send("username=chao&password=123456"); xmlHttp.onreadystatechange = function () { if (xmlHttp.readyState === 4 && xmlHttp.status === 200) { alert(xmlHttp.responseText); } }; };
2.3.Ajax-服务器-Ajax流程图:
2.4 ajax参数:
请求参数: ######################------------data---------################ data: 当前ajax请求要携带的数据,是一个json的object对象,ajax方法就会默认地把它编码成某种格式 (urlencoded:?a=1&b=2)发送给服务端;此外,ajax默认以get方式发送请求。 function testData() { $.ajax("/test",{ //此时的data是一个json形式的对象 data:{ a:1, b:2 } }); //?a=1&b=2 ######################------------processData---------################ processData:声明当前的data数据是否进行转码或预处理,默认为true,即预处理;if为false, 那么对data:{a:1,b:2}会调用json对象的toString()方法,即{a:1,b:2}.toString() ,最后得到一个[object,Object]形式的结果。 ######################------------contentType---------################ contentType:默认值: "application/x-www-form-urlencoded"。发送信息至服务器时内容编码类型。 用来指明当前请求的数据编码格式;urlencoded:?a=1&b=2;如果想以其他方式提交数据, 比如contentType:"application/json",即向服务器发送一个json字符串: $.ajax("/ajax_get",{ data:JSON.stringify({ a:22, b:33 }), contentType:"application/json", type:"POST", }); //{a: 22, b: 33} 注意:contentType:"application/json"一旦设定,data必须是json字符串,不能是json对象 views.py: json.loads(request.body.decode("utf8")) ######################------------traditional---------################ traditional:一般是我们的data数据有数组时会用到 :data:{a:22,b:33,c:["x","y"]}, traditional为false会对数据进行深层次迭代;
响应参数:
dataType: 预期服务器返回的数据类型,服务器端返回的数据会根据这个值解析后,传递给回调函数。
默认不需要显性指定这个属性,ajax会根据服务器返回的content Type来进行转换;
比如我们的服务器响应的content Type为json格式,这时ajax方法就会对响应的内容
进行一个json格式的转换,if转换成功,我们在success的回调函数里就会得到一个json格式
的对象;转换失败就会触发error这个回调函数。如果我们明确地指定目标类型,就可以使用
data Type。
dataType的可用值:html|xml|json|text|script
见下dataType实例
三、Ajax请求设置csrf_token
方式1:
通过获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送。 {% csrf_token %} # 设置csrf_token $.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插件。
cookie下载:http://plugins.jquery.com/cookie/ <script src="{% static 'js/jquery.cookie.js' %}"></script> $.ajax({ url: "/cookie_ajax/", type: "POST", headers: {"X-CSRFToken": $.cookie('csrftoken')}, // 其实在ajax里面还有一个参数是headers,自定制请求头,可以将csrf_token加在这里,我们发contenttype类型数据的时候,从Cookie取csrftoken,并设置到请求头中 data: {"username": "chao", "password": 123456}, success: function (data) { console.log(data); } })
或者用自己写一个getCookie方法: 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。
django.views.decorators.csrf import ensure_csrf_cookie @ensure_csrf_cookie def login(request): pass
四、请求头ContentType
ContentType指的是请求体的编码类型,常见的类型共有3种:
application/x-www-form-urlencoded类型一:
这应该是最常见的 POST 提交数据的方式了。浏览器的原生 <form> 表单,如果不设置 enctype 属性,那么最终就会以 默认格式application/x-www-form-urlencoded 方式提交数据,ajax默认也是这个。请求类似于下面这样(无关的请求头在本文中都省略掉了): POST http://www.example.com HTTP/1.1 Content-Type: application/x-www-form-urlencoded;charset=utf-8 user=yuan&age=22 # 这就是上面这种contenttype规定的数据格式,后端对应这个格式来解析获取数据,不管是get方法还是post方法,都是这样拼接数据,大家公认的一种数据格式,但是如果你contenttype指定的是urlencoded类型,但是post请求体里面的数据是下面那种json的格式,那么就出错了,服务端没法解开数据。
看network来查看我们发送的请求体:
multipart/form-data类型二:
这又是一个常见的 POST 数据提交的方式。我们使用表单上传文件时使用,必须让 <form> 表单的 enctype 等于 multipart/form-data,form表单不支持发json类型的contenttype格式的数据,而ajax什么格式都可以发,也是ajax应用广泛的一个原因。 例子: POST http://www.example.com HTTP/1.1 Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA ------WebKitFormBoundaryrGKCBY7qhFd3TrwA Content-Disposition: form-data; name="user" chao ------WebKitFormBoundaryrGKCBY7qhFd3TrwA Content-Disposition: form-data; name="file"; filename="chrome.png" Content-Type: image/png PNG ... content of chrome.png ... ------WebKitFormBoundaryrGKCBY7qhFd3TrwA-- 这个例子稍微复杂点。首先生成了一个 boundary 用于分割不同的字段,为了避免与正文内容重复,boundary 很长很复杂。然后 Content-Type 里指明了数据是以 multipart/form-data 来编码,本次请求的 boundary 是什么内容。
消息主体里按照字段个数又分为多个结构类似的部分,每部分都是以 --boundary 开始,紧接着是内容描述信息,然后是回车,最后是字段具体内容(文本或二进制)。
如果传输的是文件,还要包含文件名和文件类型信息。消息主体最后以 --boundary-- 标示结束。
application/json 类型三:
application/json 这个 Content-Type 作为响应头大家肯定不陌生。实际上,现在越来越多的人把它作为请求头,用来告诉服务端消息主体是序列化后的 JSON 字符串。由于 JSON 规范的流行,除了低版本 IE 之外的各大浏览器都原生支持 JSON.stringify,服务端语言也都有处理 JSON 的函数,使用 JSON 不会遇上什么麻烦。
如果在ajax里面写上这个contenttype类型,那么data参数对应的数据,就不能是个object类型数据了,必须是json字符串,contenttype:'json',简写一个json,它也能识别是application/json类型
html文件发送后端的数据:(默认格式: 类型一)数据如果是非默认格式时,必须指定数据的格式:
控制台查看数据的详细信息:
当前django后端还不支持json数据的解析,只能我们自己来解析数据格式,原始数据存放在request.body中:
$.ajax({ url:"{% url 'home' %}", type:'post', headers:{ "X-CSRFToken":$.cookie('csrftoken'), # 处理cssrf_token contentType:'json', }, data:JSON.stringify({ //如果我们发送的是json数据格式的数据,那么csrf_token就不能直接写在data里面了,没有效果,必须通过csrf的方式3的形式来写,写在hearders(请求头,可以写一些自定制的请求头)里面,注意,其实contentType也是headers里面的一部分,写在里面外面都可以 name:name, //csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(), }), success:function (response) { } })
前端返回后端的实例:
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>序列化测试</h1> <form> 用户名:<input type="text" name="ajaxname"> 密码:<input type="password" name="ajaxpwd"> <input type="button" value="提交" id="btn"> </form> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script> <script src="{% static 'js/jquery.cookie.js' %}"></script> <script> $("#btn").click(function () { var username = $("[name=ajaxname]").val(); var password = $("[name=ajaxpwd]").val(); var csrf_data = $("[name=csrfmiddlewaretoken]").val(); $.ajax({ url: {% url "home1" %}, type: "post", data: JSON.stringify({ {# 序列化 :如果我们发送的是json数据格式的数据,那么csrf_token就不能直接写在data里面了,没有效果,必须通过csrf的方式3的形式来写,写在hearders(请求头,可以写一些自定制的请求头)里面,注意,其实contentType也是headers里面的一部分,写在里面外面都可以#} username: username, password: password, {#csrfmiddlewaretoken: csrf_data,#} {# 序列化不能在这里面处理csrf_token,可以在headers里面处理 #} }), headers: { "X-CSRFToken": $.cookie("csrftoken"), {# 这里处理csrf_token #} contentType: "json", {# 指定发送的数据类型 #} }, success: function (data) { console.log(data); } }) }) </script> </body> </html>
# json序列化,后端接收json类型的字符串 def home1(request): import json if request.method == "GET": return render(request, "home.html") else: # username = request.POST.get("username") # None # password = request.POST.get("password") # None print(request.POST) # 获取结果为<QueryDict: {'{"username":"alex","password":"123"}': ['']}> print(request.body) # django没有json反序列化解析器,只能把json的内容放在body里 info_str = request.body.decode("utf-8") # 解码 info_dict = json.loads(info_str) # 字符串反序列化 username = info_dict["username"] password = info_dict["password"] print(username, password) return HttpResponse("ok")
后端提交数据到前端实例:
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>序列化测试,请打开控制台查看结果!</h1> <form> <input type="button" value="提交" id="btn"> </form> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script> <script src="{% static 'js/jquery.cookie.js' %}"></script> <script> $("#btn").click(function () { $.ajax({ url: {% url "home2" %}, type: "post", headers: { "X-CSRFToken": $.cookie("csrftoken"), }, success: function (data) { console.log(data); } }) }) </script> </body> </html>
# 后端提交数据 def home2(request): import json if request.method == "GET": return render(request, "home2.html") else: # 方式一:手动序列化 res = {'status': 0, 'info': [11, 22, 33]} res_str = json.dumps(res) return HttpResponse(res_str, content_type='application/json') # 可以简写content_type='json',指定消息格式 return HttpResponse(res_str) # 方式二:自动序列化 from django.http import JsonResponse res1 = {'status': 0, 'info': [11, 22, 33]} return JsonResponse(res1) res2 = [11, 22, 33] return JsonResponse(res2, safe=False) # 序列的数据不是字典类型,需要safe=False # 方式三:models数据通过values提取数据,转化成dict类型 from app01 import models book_objs = models.Book.objects.all().values('title', 'price') books = list(book_objs) return JsonResponse(books, safe=False) # 方式四:django序列化模块 from django.core import serializers from app01 import models book_objs = models.Book.objects.all() res = serializers.serialize('json', book_objs) # json:指定序列化类型 print(res, type(res)) return HttpResponse(res)
五、基于form表单文件上传
基于form表单的模板部分:
<form action="" method="post" enctype="multipart/form-data"> # 上面说的其他两种contenttype都是键值的形式发送数据,这种form_data的格式一般是把大数据一段一段隔开的 用户名 <input type="text" name="user"> 头像 <input type="file" name="avatar"> # 如果不用form_data格式来发,那么默认的是urlencoded的格式,这个标签的数据会组成 avatar:文件名字 来进行发送 <input type="submit"> </form>
视图部分: def index(request): print(request.body) # 原始的请求体数据 print(request.GET) # GET请求数据 print(request.POST) # POST请求数据 print(request.FILES) # 上传的文件数据 return render(request,"index.html")
upload.py,内容如下: def upload(request): if request.method == 'GET': return render(request,'upload.html') else: print(request.POST) username = request.POST.get('user') file_obj = request.FILES.get('file_obj') #获得文件数据对象 print('>>>',file_obj,type(file_obj)) #>>> jaden博客.txt <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>,一个文件对象,可以理解为一个文件句柄 file_name = file_obj.name #jaden博客.txt print(file_name) # 将数据写到文件里面,需要名字,需要数据 with open(file_name,'wb') as f: #直接把文件名字放这里,那么文件将直接生成在django的整个项目目录下,因为django配置的系统搜索的根路径就是咱们的项目文件夹路径,那个BASE_DIR,一般我们需要自己建立一个文件夹专门存放上传的文件 # 所以需要我们自己来拼接一个路径放到这里,os.path.join(settings.BASE_DIR,'media','img',file_name) # f.write() #不能一下写进去,占用的内容太多,要一点一点写,方式一 for data in file_obj: # 读数据,方式二 f.write(data) #每次读取的data不是固定长度的,和读取其他文件一样,每次读一行,识别符为\r \n \r\n,遇到这几个符号就算是读了一行
# 方式三 #for chunks in file_obj.chunks(): # chunks()默认一次返回大小为经测试为65536B,也就是64KB,最大为2.5M,是一个生成器 # f.write(chunks)
六、基于ajax文件上传
模板: <form> #用不用form没关系,这里就是个盒子的作用,一般写form标签是为了提示别人,这个地方的内容是要提交的 {% csrf_token %} 用户名 <input type="text" id="user"> 头像 <input type="file" id="avatar"> <input type="button" id="ajax-submit" value="ajax-submit"> </form> <script> $("#ajax-submit").click(function(){ var formdata=new FormData(); #ajax上传文件的时候,需要这个类型,它会将添加给它的键值对加工成formdata的类型 formdata.append("user",$("#user").val()); #添加键值的方法是append,注意写法,键和值之间是逗号 formData.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val()); #别忘了csrf_token formdata.append("avatar_img",$("#avatar")[0].files[0]); $.ajax({ url:"", type:"post", data:formdata, #将添加好数据的formdata放到data这里 processData: false , // 不处理数据 contentType: false, // 不设置内容类型 success:function(data){ console.log(data) } }) }) </script>
或者使用: var form = document.getElementById("form1"); var fd = new FormData(form); 这样也可以直接通过ajax 的 send() 方法将 fd 发送到后台。
注意:由于 FormData 是 XMLHttpRequest Level 2 新增的接口,现在 低于IE10 的IE浏览器不支持 FormData。
视图: def index(request): if request.is_ajax(): print(request.body) # 原始的请求体数据 print(request.GET) # GET请求数据 print(request.POST) # POST请求数据 print(request.FILES) # 上传的文件数据 return HttpResponse("ok") return render(request,"index.html")
检查浏览器的请求头:
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryaWl9k5ZMiTAzx3FT
当Django处理上传一个文件的时候,文件数据被放在request.FILES中。这个文档解释文件怎么样被存储在磁盘上或者内存中,怎样定制默认的行为。 基本文件上传 考虑一个包含FileField的简单的表单: from django import forms class UploadFileForm(forms.Form): title=forms.CharField(max_length=50) file=forms.FileField() 一个处理这个表单的视图将在request.FILES中接受文件数据 ,request.FILES是一个字典,它对每个FileField(或者是ImageField,或者是其他的FileField的子类)都包含一个key.所以 从上面的表单中来的数据将可以通过request.FILES['file']键来访问. 注意request.FILES只有 在request方法是POST并且发出POST请求的 有属性enctype="multipart/form-data".否则,request。FILES将是空的。 看另一个简单的; from fdjango.http improt HttpResponseRedirect from django.shortcuts import render_to_response from somewhere import handle_uploaded_file def upload_file(request): if request.method == 'post': form = UploadFileForm(rquest.POST,request.FILES) if form.is_valid(): handle_uploaded_file(request.FILES['file']) return HttpResponseRedirect('/success/ur/') else: form = UploadFileForm() return render_to_response('upload.html',{'form':form}) 要注意,我们必须将request.FILES传递到表单的构造器中;这就是文件数据怎样和表单沾上边的 。 处理上传的文件 最后的难题是怎样处理从request.FILES中获得的真实的文件。这个字典的每个输入都是一个UploadedFile对象——一个上传之后的文件的简单的包装。 你通常会使用下面的几个方法来访问被上传的内容: UploadedFile.read():从文件中读取整个上传的数据。小心整个方法:如果这个文件很大,你把它读到内存中会弄慢你的系统。你可以想要使用chunks()来代替,看下面; UploadedFile.multiple_chunks():如果上传的文件足够大需要分块就返回真。默认的这个值是2.5兆,当然这个值是可以调节的,看下面的UploadedFile.chunks():一个产生器,返回文件的块。如果multiple_chunks()是真的话,你应该在一个循环中使用这个方法,而不是使用read(); UploadedFile.name:上传文件的名字(比如m_file.txt) UploadedFile.size:以bytes表示的上传的文件的大小。 还有其他的几个方法和属性。你可以自己去查。 把他们放在一起,这里是一个你处理上传文件的通常方法: def handle_uploaded_file(f): destination = open('some/file/name.txt','wb+') for chunk in f.chunks(): destination.write(chunk) destination.close() 在UploadedFile.chunks()上循环而不是用read()保证大文件不会大量使用你的系统内存。 上传的数据存在哪里? 在你保存上传的文件之前,数据需要被保存在某些地方。默认呢的,如果一个上传的文件小于2.5兆,Django会将上传的东西放在内存里。这意味着只要从内存读取数据并保存到硬盘上,所以很快。然而,如果一个上传的文件太大,Django将将上传的文件写到一个临时的文件中,这个文件在你的临时文件路径中。在Unix-like的平台上意味着你可以预见Django产生一个文件保存为/tmp/tmpzfp6I6.upload的文件。如果这个文件足够大,你可以观察到这个文件的大小在增大。 很多细节--2.5M;/tmp;等 等 都是简单的看上去合理的默认值。继续阅读看看你怎么样个性化或者完全替代掉上传行为。 改变上传处理行为 三个设置改变Django的上传处理行为: FILE_UPLOAD_MAX_MEMORY_SIZE:以bytes为单位的到内存中的最大大小,。比这个值大的文件将被先存到磁盘上。默认是2.5兆 FILE_UPLOAD_TEMP_DIR:比FILE_UPLOAD_MAX_MEMORY_SIZE大的文件将被临时保存的地方。默认是系统标准的临时路径。 FILE_UPLOAD_PERMISSIONS:如果这个没有给出或者是None,你将获得独立于系统的行为。大多数平台,临时文件有一个0600模式,从内存保存的文件将使用系统标准umask。 FILE_UPLOAD_HANDLERS:上传文件的处理器。改变这个设置允许完全个性化——甚至代替——Django的上传过程。 默认是: ("django.core.files.uploadhandler.MemoryFileUploadHandler", "django.core.files.uploadhandler.TemporaryFileUploadHandler",) UploadedFile 对象 class UploadedFile 作为那些重File继承的补充,素有的UploadedFile对象定义了下面的方法和属性: UploadedFile.content_type 文件的content_type头(比如text/plain orapplication/pdf )。像用户提供的任何数据一样,你不应该信任上传的数据就是这个类型。你仍然要验证这个文件包含这个头声明的content-type——“信任但是验证”。 UploadedFile.charset 对于text/*的content-types,浏览器提供的字符集。再次,“信任但是验证”是最好的策略。 UploadedFile.temporary_file_path():只有被传到磁盘上的文件才有这个方法,它返回临时上传文件的全路径。 注意: 像通常的Python文件,你可以迭代上传的文件来一行一行得读取文件: for line in uploadedfile: do_something_with(line) 然而,不同于标准Python文件,UploadedFile值懂得/n(也被称为Unix风格)的结尾。如果你知道你需要处理有不同风格结尾的文件的时候,你要在你的视图中作出处理。 上传处理句柄: 当一个用户上传一个文件,Django敬爱那个这个文件数据传递给上传处理句柄——一个处理随着文件上传处理文件的小类。上传处理句柄被FILE_UPLOAD_HANDLERS初始化定义,默认是: ( "django.core.files.uploadhandler.MemoryFileUploadHandler" , "django.core.files.uploadhandler.TemporaryFileUploadHandler" ,) 这两个提供了Django处理小文件和大文件的默认上产行为。 你可以个性化处理句柄来个性化Django处理文件的行为。比如你可以使用个性化的处理句柄来强制用户配额,实时地压缩数据,渲染进度条,甚至在保存在本地的同时向另一个存储地发送数据。 实时修改上传处理句柄 有的时候某些视图要使用不同的上传行为。这种情况下,你可以重写一个上传处理句柄,通过request.upload_handlers来修改。默认的,这个列表包含FILE_UPLOAD_HANDLERS提供的处理句柄,但是你可以像修改其他列表一样修改这个列表。 比如,加入你写了一个叫做 ProgressBarUploadHandler 的处理句柄。你可以通过下面的形式加到你的上传处理句柄中: request.upload_handlers.insert(0,ProgressBarUploadHandler()) 你赢使用list.insert()在这种情况下。因为进度条处理句柄需要首先执行。记住,处理句柄按照顺序执行。 如果你像完全代替掉上传处理句柄,你可以赋值一个新的列表: request.upload_handlers=[ProgressBarUploadHandler()] 注意:你只能在访问request.POST或者request.FILES之前修改上传处理句柄。——如果上传处理开始后再改就没用了。如果你在修改reqeust.uplaod_handlers之前访问了request.POST or request.FILES ,Django将抛出一个错误。 所以,在你的视图中尽早的修改上传处理句柄。 写自定义的上传处理句柄: 所有的上传处理句柄都应 是 django.core.files.uploadhandler.FileUploadHandler的子类。你可以在任何你需要的地方定义句柄。 需要的方法: 自定义的上传处理句柄必须定义一下的方法: FileUploadHandler.receive_data_chunk(self,raw_data,start):从文件上传中接收块。 raw_data是已经上传的字节流 start是raw_data块开始的位置 你返回的数据将被传递到下一个处理句柄的receive_data_chunk方法中。这样一个处理句柄就是另一个的过滤器了。 返回None将阻止后面的处理句柄获得这个块,当你 自己存储这个数据,而不想其他处理句柄存储拷贝时很有用。 如果你触发一个StopUpload或者SkipFile异常,上传将被放弃或者文件被完全跳过。 FileUploadHandler.file_complete(self, file_size) 当 文件上传完毕时调用。 处理句柄应该返回一个UploadFile对象,可以存储在request.FILES中。处理句柄也可以返回None来使得UploadFile对象应该来自后来的上传处理句柄。 剩下的就是可选的一些方法实现。 FILE_UPLOAD_MAX_MEMORY_SIZE = 209715200 FILE_UPLOAD_MAX_MEMORY_SIZE = 209715200 在你本机先好好测试一下,它是如何占用内存,什么时候开始存入temp目录,怎么迁移到upload目录底下的 文件上传的时候,如果一个上传的文件小于2.5兆,Django会将上传的东西放在内存里,如果上传的文件大于2.5M,Django将整个上传的文件写到一个临时的文件中,这个文件在临时文件路径中。上传完毕后,将调用View中的_Upload()方法将临时文件夹中的临时文件分块写到上传文件的存放路径下,每块的大小为64K,写完后临时文件将被删除。 UploadedFile.multiple_chunks():如果上传的文件足够大需要分块就返回真。默认的这个值是2.5兆,当然这个值是可以调节的,看下面的UploadedFile.chunks():一个产生器,返回文件的块。如果multiple_chunks()是真的话,你应该在一个循环中使用这个方法,而不是使用read(); 在你保存上传的文件之前,数据需要被保存在某些地方。默认呢的,如果一个上传的文件小于2.5兆,Django会将上传的东西放在内存里。这意味着只要从内存读取数据并保存到硬盘上,所以很快。然而,如果一个上传的文件太大,Django将上传的文件写到一个临时的文件中,这个文件在你的临时文件路径中。在Unix-like的平台上意味着你可以预见Django产生一个文件保存为/tmp/tmpzfp6I6.upload的文件。如果这个文件足够大,你可以观察到这个文件的大小在增大。 三个设置改变Django的上传处理行为: FILE_UPLOAD_MAX_MEMORY_SIZE:以bytes为单位的到内存中的最大大小,。比这个值大的文件将被先存到磁盘上。默认是2.5兆 FILE_UPLOAD_TEMP_DIR:比FILE_UPLOAD_MAX_MEMORY_SIZE大的文件将被临时保存的地方。默认是系统标准的临时路径。 FILE_UPLOAD_PERMISSIONS:如果这个没有给出或者是None,你将获得独立于系统的行为。大多数平台,临时文件有一个0600模式,从内存保存的文件将使用系统标准umask。
七、关于json
7.1 什么是json
- JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
- JSON 是轻量级的文本数据交换格式
- JSON 独立于语言 *
- JSON 具有自我描述性,更易理解
* JSON 使用 JavaScript 语法来描述数据对象,但是 JSON 仍然独立于语言和平台。JSON 解析器和 JSON 库支持许多不同的编程语言。
json数据类型和python数据类型的对比:
注意:
object和python的dict类型是差不多的,但是要求里面必须是双引号,
string和list、tuple等也是一样的,都是双引号。
python中的datetime等时间日期类型是不能进行json序列化的,因为json没有对应的格式,
上面的这几种数据类型虽然进行json.dumps序列化之后都是个字符串,但是也是有格式的:
7.2 js的stringify与parse方法:
JavaScript中关于JSON对象和字符串转换的两个方法: JSON.parse(): 用于将一个 JSON 字符串转换为 JavaScript 对象 JSON.parse('{"name":"chao"}'); JSON.stringify(): 用于将 JavaScript 值转换为 JSON 字符串。 JSON.stringify({"name":"chao"})
7.3 Django内置的serializers做序列化:
示例: def books_json(request): book_list = models.Book.objects.all()[0:10] from django.core import serializers # 导入这个serializers这个类 ret = serializers.serialize("json", book_list) # 指定需要转换成的格式:json return HttpResponse(ret)
7.4 自定义序列化:
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)
八、补充一个SweetAlert插件示例
$(".btn-danger").on("click", function () { 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: "/delete_book/", type: "post", data: {"id": deleteId}, success: function (data) { if (data.status === 1) { swal("删除成功!", "你可以准备跑路了!", "success"); } else { swal("删除失败", "你可以再尝试一下!", "error") } } }) }); })
九、SweetAlert 项目实例
注意:配置静态文件及数据文件配置
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^create_book/', views.create_book, name='create_book'), url(r'^show/', views.show, name='show'), url(r'^edit_book/(\d+)/', views.edit_book, name='edit_book'), url(r'^delete_book/(\d+)/', views.delete_book, name='delete_book'), url(r'^ajax_delete_book/(\d+)/', views.ajax_delete_book, name='ajax_delete_book'), url(r'^mt_edit_book/(\d+)/', views.mt_edit_book, name='mt_edit_book'), ]
from django.shortcuts import render, HttpResponse, redirect from django import forms from app01 import models from django.http import JsonResponse import json class MyForm(forms.Form): title = forms.CharField( max_length=32, min_length=2, error_messages={ "min_length": '长度不能小于2', "required": '该字段不能为空!', "max_length": '字段过长,不能超过32位!' }, label='书名', widget=forms.widgets.TextInput(attrs={'placeholder': '用户名'}) ) price = forms.IntegerField( label='价格', widget=forms.widgets.NumberInput(attrs={'placeholder': '价格'}) ) publishDate = forms.DateField( label='出版日期', widget=forms.widgets.DateInput(attrs={'type': 'date'}) ) publish = forms.ModelChoiceField( label='出版社', queryset=models.Publish.objects.all(), widget=forms.widgets.Select() ) authors = forms.ModelMultipleChoiceField( label='作者', queryset=models.Author.objects.all(), widget=forms.widgets.SelectMultiple() ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for field in self.fields: self.fields[field].widget.attrs.update({ 'class': 'form-control', }) # 添加新的书籍 def create_book(request): if request.method == 'GET': form_obj = MyForm() return render(request, 'index.html', {'form_obj': form_obj}) else: data = request.POST form_obj = MyForm(data) if form_obj.is_valid(): # 验证每个字段传过来的数据是不是正确的 data = form_obj.cleaned_data author_data = data.pop('authors') # book中没有author_data字段 book_obj = models.Book.objects.create(**data) book_obj.authors.add(*author_data) return redirect('show') else: print(form_obj.errors) return render(request, 'index.html', {'form_obj': form_obj}) # 模态添加书籍 def mt_edit_book(request, n): if request.method == "POST": data = request.POST.dict() author_str = data.get("authors") author_data = json.loads(author_str) print(author_data) del data["csrfmiddlewaretoken"] del data["authors"] print(data) book_obj = models.Book.objects.filter(pk=int(n)) book_obj.update(**data) author_list = [int(author) for author in author_data] book_obj[0].authors.set(author_list) return HttpResponse("ok") # 显示书籍 def show(request): all_books = models.Book.objects.all() print(all_books.values("publishDate")) all_publish = models.Publish.objects.all() all_authors = models.Author.objects.all() # all_books = models.Book.objects.all().first() # all_books.authors.all() #多对多 # all_books.publish.name #一对多 return render(request, 'show.html', {'all_books': all_books, "all_publish": all_publish, "all_authors": all_authors}) # 编辑书籍 def edit_book(request, n): book_obj = models.Book.objects.filter(pk=n) if request.method == 'GET': book_obj = book_obj.first() all_publish = models.Publish.objects.all() all_authors = models.Author.objects.all() return render(request, 'edit_book.html', {'n': n, 'book_obj': book_obj, 'all_publish': all_publish, 'all_authors': all_authors}) else: author_data = request.POST.getlist('authors') # 取多选数据的时候用getlist方法 print('author_data', author_data) # author_data ['2', '3'] data = request.POST.dict() print(data) del data['csrfmiddlewaretoken'] data.pop('authors') # authors:[1,2] book_obj.update(**data) book_obj[0].authors.set(author_data) return redirect('show') # 删除书籍(form表单) def delete_book(request, n): models.Book.objects.filter(pk=n).delete() return redirect('show') # 删除书籍(ajax静态删除) def ajax_delete_book(request, n): data = {'status': 0} try: data['status'] = 1 models.Book.objects.filter(pk=n).delete() except Exception: data['status'] = 2 return JsonResponse(data)
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}" rel="stylesheet"> </head> <body> <h1>这是编辑页面</h1> <div class="container-fluid"> <div class="row"> <div class="col-md-8 col-md-offset-2" > <form action="{% url 'edit_book' n %}" method="post"> <div class="form-group"> <label for="">书名</label> <input class="form-control" type="text" value="{{ book_obj.title }}" name="title"> </div> <div class="form-group"> <label for="">出版日期</label> <input class="form-control" name="publishDate" type="date" value="{{ book_obj.publishDate|date:'Y-m-d' }}"> </div> <div class="form-group"> <label for="">价格</label> <input class="form-control" type="number" value="{{ book_obj.price }}" name="price"> </div> {% csrf_token %} <div class="form-group"> <label for="">出版社</label> <select class="form-control" name="publish" id=""> {% for publish in all_publish %} {% if book_obj.publish == publish %} <option selected value="{{ publish.pk }}">{{ publish.name }}</option> {% else %} <option value="{{ publish.pk }}">{{ publish.name }}</option> {% endif %} {% endfor %} </select> </div> <div class="form-group"> <label for="">作者</label> <select class="form-control" name="authors" id="" multiple> {% for author in all_authors %} {% if author in book_obj.authors.all %} <option selected value="{{ author.pk }}">{{ author.name }}</option> {% else %} <option value="{{ author.pk }}">{{ author.name }}</option> {% endif %} {% endfor %} </select> </div> <input type="submit" class="btn btn-success pull-right"> </form> </div> </div> </div> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script> <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script> <script> </script> </body> </html>
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}" rel="stylesheet"> </head> <body> <div> <form action="{% url 'home' %}" method="post" novalidate> {% csrf_token %} <div> {{ form_obj.errors }} </div> {{ form_obj.name.label }} {{ form_obj.name }} {{ form_obj.name.errors.0 }} <div> {{ form_obj.password.label }} {{ form_obj.password }} {{ form_obj.password.errors.0 }} </div> <div> {{ form_obj.r_password.label }} {{ form_obj.r_password }} {{ form_obj.r_password.errors.0 }} </div> <input type="submit"> </form> </div> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script> <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script> <script> </script> </body> </html>
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}" rel="stylesheet"> </head> <body> <h1> 这是添加页面 </h1> {#{{ form_obj.as_p }}#} <div class="container-fluid"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <form action="{% url 'create_book' %}" method="post" novalidate> {{ form_obj.errors }} {% csrf_token %} {% for field in form_obj %} <div class="form-group {% if field.errors.0 %} has-error {% endif %}"> <label for="{{ field.id_for_label }}"> {{ field.label }}</label> {{ field }} <span class="text-success">{{ field.help_text }}</span> <span class="text-danger">{{ field.errors.0 }}</span> </div> {% endfor %} <input type="submit" class="btn btn-success pull-right" value="保存"> </form> </div> </div> </div> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script> <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script> <script> </script> </body> </html>
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}" rel="stylesheet"> <link href="{% static 'dist/sweetalert.css' %}" rel="stylesheet"> </head> <body> <h1>数据展示页面</h1> <div class="container-fluid"> <div class="row"> <div class="col-md-8 col-md-offset-2"> <a class="btn btn-primary" href="{% url 'create_book' %}"> 添加书籍 </a> <table class="table-bordered table table-striped table-hover"> <thead> <tr> <th>序列号</th> <th>书名</th> <th>出版日期</th> <th>价格</th> <th>出版社</th> <th>作者</th> <th>操作</th> </tr> </thead> <tbody> {% for book in all_books %} <tr> <td>{{ forloop.counter }}</td> <td>{{ book.title }}</td> <td>{{ book.publishDate|date:'Y-m-d' }}</td> <td>{{ book.price }}</td> <td>{{ book.publish.name }}</td> <td> {% for author in book.authors.all %} {{ author.name }} {% if forloop.last %} {% else %} , {% endif %} {% endfor %} </td> <td> <a href="{% url 'edit_book' book.pk %}" class="btn btn-warning">编辑</a> <button type="button" class="btn btn-success mt-edit" data-toggle="modal" data-target="#myModal"><span class="hide">{% url 'mt_edit_book' book.pk %}</span> 模态编辑 </button> <a href="{% url 'delete_book' book.pk %}" class="btn btn-danger">form删除</a> <button class="btn btn-danger ajaxbtn">ajax删除</button> <span class="hidden">{{ book.pk }}</span> </td> </tr> {% endfor %} </tbody> </table> <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="myModalLabel">添加书籍</h4> </div> <div class="modal-body"> <form action="" method="post"> <div class="form-group"> <label for="">书名</label> <input class="form-control" type="text" value="{{ book_obj.title }}" name="title"> </div> <div class="form-group"> <label for="">出版日期</label> <input class="form-control" name="publishDate" type="date" value="{{ book_obj.publishDate|date:'Y-m-d' }}"> </div> <div class="form-group"> <label for="">价格</label> <input class="form-control" type="number" value="{{ book_obj.price }}" name="price"> </div> {% csrf_token %} <div class="form-group"> <label for="">出版社</label> <select class="form-control" name="publish" id=""> {% for publish in all_publish %} {% if book_obj.publish == publish %} <option selected value="{{ publish.pk }}">{{ publish.name }}</option> {% else %} <option value="{{ publish.pk }}">{{ publish.name }}</option> {% endif %} {% endfor %} </select> </div> <div class="form-group"> <label for="">作者</label> <select class="form-control" name="authors" id="" multiple> {% for author in all_authors %} {% if author in book_obj.authors.all %} <option selected value="{{ author.pk }}">{{ author.name }}</option> {% else %} <option value="{{ author.pk }}">{{ author.name }}</option> {% endif %} {% endfor %} </select> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-default mt-close" data-dismiss="modal" id="no">关闭 </button> <button type="button" class="btn btn-primary mt-submit" id="yes">提交</button> </div> </div> </div> </div> </div> </div> </div> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script> <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script> <script src="{% static 'dist/sweetalert.min.js' %}"></script> <script> {# ajax删除 #} $("tbody").on("click", '.ajaxbtn', function () { {# 通过事件委托处理$(".ajaxbtn")点击事件 #} {#var ths = $(this);#} // 方式一 swal({ title: "Are you sure!", text: "don't be fool!", type: "warning", showCancelButton: true, confirmButtonClass: "btn-danger", confirmButtonText: "oh,year!", cancelButtonText: "oh,no!", closeOnConfirm: false }, // function () { 方式一:通过变量形式获取到ths的值的传统写法 () => { //箭头函数改变$(this)的指向,此时的$(this)指向的是$(".ajaxbtn")事件本身,方式二 {#console.log(ths);#} {#var deleteId = ths.next().text();#} // 通过变量形式获取到ths的值(方式一) var deleteId = $(this).next().text(); // 箭头函数(方式二) console.log(deleteId); var ths = $(this); $.ajax({ {#url: "{% url 'delete_book' deleteId %}",#} // 变量不能直接放在里面,需要通过下面字符串拼接的方式处理url url: "/ajax_delete_book/" + deleteId + '/', type: "post", data: {"csrfmiddlewaretoken": "{{ csrf_token }}"}, {# 处理csrf_token的另一种方式 #} success: function (data) { if (data.status === 1) { swal("删除成功!", "你可以准备跑路了!", "success"); ths.parent().parent().remove(); var tr_list = $('tbody').children(); // 找到每个tr标签 $.each(tr_list, function (k, v) { // 通过each函数,遍历tr标签,重新排序 console.log(k, v); $(v).children().eq(0).text(k + 1); }) } else { swal("删除失败", "你可以再尝试一下!", "error") } } }) }); }); {# 模态编辑 #} $(".mt-edit").on("click", function () { var title = $(this).parent().parent().children().eq(1).text(); var publishDate = $(this).parent().parent().children().eq(2).text(); var price = $(this).parent().parent().children().eq(3).text(); var publish = $(this).parent().parent().children().eq(4).text(); var author = $(this).parent().parent().children().eq(5).text(); $("[name=title]").val(title); $("[name=publishDate]").val(publishDate); $("[name=price]").val(price); var edit_num = $(this).parent().parent().children().eq(0).text(); var mt_url = $(this).children().text() console.log(mt_url) $(".mt-submit").click(function () { var title1 = $("[name=title]").val(); var publishDate1 = $("[name=publishDate]").val(); var price1 = $("[name=price]").val(); var publish1 = $("[name=publish]").val(); var author1 = $("[name=authors]").val(); console.log(author1); $.ajax({ url: mt_url, type: "post", data: { "csrfmiddlewaretoken": "{{ csrf_token }}", "title": title1, "publishDate": publishDate1, "price": price1, "publish": publish1, "authors": JSON.stringify(author1), }, success: function (data) { location.reload(); console.log(data) } }) }) }) </script> </body> </html>
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}" rel="stylesheet"> </head> <body> <div> <form action="/test/" method="post" novalidate> {% csrf_token %} {{ form.keep.label }} {{ form.keep }} {{ form.keep.errors.0 }} <input type="submit"> </form> </div> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script> <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script> <script> </script> </body> </html>
from django.db import models class Author(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) age = models.IntegerField() authorDetail = models.OneToOneField(to="AuthorDetail", to_field="nid") def __str__(self): return self.name class AuthorDetail(models.Model): nid = models.AutoField(primary_key=True) birthday = models.DateField() telephone = models.BigIntegerField() addr = models.CharField(max_length=64) class Publish(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField() def __str__(self): return self.name class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_length=32) publishDate = models.DateField() price = models.DecimalField(max_digits=5, decimal_places=2) publish = models.ForeignKey(to="Publish", to_field="nid") authors = models.ManyToManyField(to='Author', ) def __str__(self): return self.title