python项目Django(AJAX)

一 、Ajax简介

  1.1 简介:

    AJAXAsynchronous Javascript And XML)翻译成中文就是异步的JavascriptXML”。即使用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>
login.html
  
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>
    欢迎来到xxx官网
</h1>
</body>
</html>
base.html
  
url(r'^login/', views.login,name='login'),
url(r'^home/', views.home,name='home'),
urls.py
  
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')
views.py

二、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>
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")
views.py文件

  后端提交数据到前端实例:

  
{% 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>
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)
View.py

五、基于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。
关于django后端代码接受上传文件的方法

七、关于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插件示例

  点击下载Bootstrap-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'),

]
urls.py文件
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)
views.py文件
{% 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>
edit_book.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>
home.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>
index.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">&times;</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>
show.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>
test.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
models.py文件

 

posted @ 2019-05-29 18:09  Amorphous  阅读(837)  评论(0编辑  收藏  举报