Django之ajax

一:JSON基础概念

(1)定义:

  (1):JSON是指JS对象表示方法

  (2):JSON是轻量级文本数据交互格式

  (3):JSON具有自我描述性 更易理解

(2)图解:

Django之ajax

 (3)JSON语法规范

(1)其只认双引号的字符串:

["one", "two", "three"]
{ "one": 1, "two": 2, "three": 3 }
{"names": ["张三", "李四"] }
[ { "name": "张三"}, {"name": "李四"} ] 
规范的JSON格式
复制代码
{ name: "张三", 'age': 32 }  // 属性名必须使用双引号
[32, 64, 128, 0xFFF] // 不能使用十六进制值
{ "name": "张三", "age": undefined }  // 不能使用undefined
{ "name": "张三",
  "birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'),
  "getName":  function() {return this.name;}  // 不能使用函数和日期对象
}
不规范的JSON格式

二:Ajax基础简介

(1)AJAXAsynchronous Javascript And XML)翻译成中文就是异步的JavascriptXML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。

(2)AJAX 不是新的编程语言,而是一种使用现有标准的新方法。

(3)AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。(这一特点给用户的感受是在不知不觉中完成请求和响应过程)

(4)AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。

  • 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
  • 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求

PS:异步提交 局部刷新

(5)示例:页面输入两个整数 点击求和 触发后端代码执行

def index(request):
    if request.method == 'POST':
        d1 = request.POST.get('d1')
        d2 = request.POST.get('d2')
 
        # 前端传入的是字符串 转成整形 进行相加
        res = int(d1) + int(d2)
        return HttpResponse(res)
    return render(request, 'index.html')
路由层
    url(r'^index/', views.index),
<input type="text" id="d1"> + <input type="text" name="" id="d2"> = <input type="text" id="d3">
<button id="d4">求和</button>


<script>

    $('#d4').click(function () {
        $.ajax(
            {
                url: '',// 提交的目的地址
                type: 'post', // 提交的数据类型
                data: {d1: $('#d1').val(), d2: $('#d2').val()},  // 传输给后端的数据
                success: function (data) {
                    $('#d3').val(data)  // 接受后端传输的数据
                }
            }
        )
    })


</script>
前端

三:前后端交互数据格式

(1)form表单提交数据

(1)默认编码格式:urlencoded

Django之ajax

(2)默认数据格式:

Django之ajax

 (3)Django后端接受数据

Django之ajax

 PS:后端接受前端传入的数据都会存入POST请求中 供用户获取数据

(2)formdata传输文件

(1)POST体

Django之ajax

 (2)Files

Django之ajax

 PS:

  (1)django后端会自动将只要符合urlencdode编码格式的数据 自动存入POST体中

  (2)如果是文件只要你指定formdata格式 会自动存入FILES中

  (3)不指定formdata上传文件

Django之ajax

 PS:如果不指定编码格式 会将文件名称存入POST体中

(3)ajax提交数据

(1)ajax默认提交方式:urlencoded

Django之ajax

 (2)Django后端接受数据

Django之ajax

 PS:Django依旧会将请求数据 存入POST体中

(3)前端ajax提交json格式的数据

 $('#d4').click(function () {
        $.ajax(
            {
                ur:"",
                type:'post',
                data: JSON.stringify({'username':'SR','age':18}),  // json 序列化 传输人内容
                contentType:'application/json', // 指告诉后端发送的数据 为json格式
                success:function (data) {
                    $('#d3').val(data)
                }
            }
        )
    })
前端代码

Django之ajax

 (4)后端接受JSON格式的数据

Django之ajax

 PS:

  (1)后端Django不会将前端传入的数据 存入post/file中 而是将其存入body请求体中

  (2)其也不会解析前端传入的数据 

(5)ajax传入文件

    $('#d4').click(function () {
        var fomDate = new FormData();   // 生成一个formdata对象 其可以传输键值对 也可以传输文件
        fomDate.append('username', 'SR');
        fomDate.append('age', 18);
        fomDate.append('file', $('#d1')[0].files[0]);
        $.ajax(
            {
                url: '',
                type: 'post',
                data: fomDate,   // 发送的数据
                processData: false,  // 告诉前端不需要处理数据
                contentType: false, // 不使用任何编码格式 后端django会自动识别编码
                success: function (data) {
                    alert(data)

                }
            }
        )

    })
前端代码

(1)前端数据格式

Django之ajax

 (2)后端数据格式

Django之ajax

 四:序列化组件

(1)作用:将后端传输给前端的格式 进行格式化 序列化

(2)产生背景:

// 前端
{% for user in user_list %} {{ user }} {% endfor %}
def user_info(request):
    user_list = models.User_info.objects.all()
    return render(request, 'user_info.html', locals())

Django之ajaxPS:

  (1)如图其拿到的一个个对象 但是其余的语言并不是认识对象 所以需要传json格式数据

(3)手动版 传json数据

def user_info(request):
    user_list = models.User_info.objects.all()
    data = []
    for user in user_list:
        # json 序列化
        data.append(json.dumps({'username':user.username}))
        data.append(json.dumps({'gender':user.get_gender_display()},ensure_ascii=False))
    return render(request, 'user_info.html', locals())
{{ data }}

Django之ajax

 PS:

  (1)上述后端代码写的比较繁琐

  (2)前端取值比较麻烦

(4)serializers序列化组件

def user_info(request):
    user_list = models.User_info.objects.all()
    res = serializers.serialize('json', user_list)
    return render(request, 'user_info.html', locals())
{{ res }}
[{
    "model": "app01.user_info",
    "pk": 1,
    "fields": {
        "username": "SR",
        "gender": 1
    }
}, {
    "model": "app01.user_info",
    "pk": 2,
    "fields": {
        "username": "tank",
        "gender": 2
    }
}, {
    "model": "app01.user_info",
    "pk": 3,
    "fields": {
        "username": "jason",
        "gender": 2
    }
}, {
    "model": "app01.user_info",
    "pk": 4,
    "fields": {
        "username": "张三",
        "gender": 1
    }
}]
前端转码展示

五:SweetAlert插件示例

(1)测试版

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    {% load static %}
    <link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}">
    <link rel="stylesheet" href="{% static 'dist/sweetalert.css' %}">
    <script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script>
    <script src="{% static 'dist/sweetalert.min.js' %}"></script>
</head>
<body>
<table class="table-hover table table-bordered table-bordered">
    <thead>

    <tr>

        <th class="text-center">姓名</th>
        <th class="text-center">性别</th>
        <th class="text-center">操作</th>

    </tr>

    </thead>
    <tbody>

    {% for user in user_list %}
        <tr>
            <td class="text-center">{{ user.username }}</td>
            <td class="text-center">{{ user.get_gender_display }}</td>

            <td class="text-center">
                <button class="btn btn-primary">编辑</button>
                {#                此时不能用id 因为如果循环 id会相同 定义一个用户id 值为主键 后端获取数据方便#}
                <button class="btn btn-danger del" user_id= {{ user.pk }}>删除</button>
            </td>

        </tr>
    {% endfor %}


    </tbody>
</table>
<script>
    $('.del').click(function () {
      swal('标题','内容','success')
    })
</script>
</body>
</html>
前端

Django之ajax

PS:如图标题会被覆盖

Django之ajax

PS:更改下h2的边距

(2)完整版:

from django.http import JsonResponse


def user_info(request):
    user_list = models.User_info.objects.all()
    if request.is_ajax():
        back_dic = {'code': 100, 'msg': ''}  # 给前端返回消息
        user_id = request.POST.get('user_id')
        models.User_info.objects.filter(pk=user_id).delete()
        back_dic['msg'] = '删除了'
        return JsonResponse(back_dic)
    return render(request, 'user_list.html', locals())
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    {% load static %}
    <link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}">
    <link rel="stylesheet" href="{% static 'dist/sweetalert.css' %}">
    <script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script>
    <script src="{% static 'dist/sweetalert.min.js' %}"></script>
     <style>
        div.sweet-alert h2{
            padding-top: 10px;
        }
    </style>
</head>
<body>
<table class="table-hover table table-bordered table-bordered">
    <thead>

    <tr>

        <th class="text-center">姓名</th>
        <th class="text-center">性别</th>
        <th class="text-center">操作</th>

    </tr>

    </thead>
    <tbody>

    {% for user in user_list %}
        <tr>
            <td class="text-center">{{ user.username }}</td>
            <td class="text-center">{{ user.get_gender_display }}</td>

            <td class="text-center">
                <button class="btn btn-primary">编辑</button>
                {#                此时不能用id 因为如果循环 id会相同 定义一个用户id 值为主键 后端获取数据方便#}
                <button class="btn btn-danger del" user_id= {{ user.pk }}>删除</button>
            </td>

        </tr>
    {% endfor %}


    </tbody>
</table>
<script>
   $('.del').click(function () {
        // 获取当前标签对象
        var $btnEle = $(this);

        swal({
          title: "你确定要删吗?",
          text: "你要是删了,你就准备跑路吧!",
          type: "warning",
          showCancelButton: true,
          confirmButtonClass: "btn-danger",
          confirmButtonText: "是的,老子就要删!",
          cancelButtonText: "算了,算了!",
          closeOnConfirm: false,
          showLoaderOnConfirm: true
        },
        function(){
            // 朝后端发送ajax请求
            $.ajax({
                url:'',
                type:'post',
                data:{'delete_id':$btnEle.attr('user_id')},
                success:function (data) {  // 后端发字典过来 前端不需要你手动转 会自动帮你转换成js自定义对象
                    if (data.code == 100){
                        {#window.location.href = '';  // 不写就是条到当前页面#}

                        // 通过DOM操作 实时改变页面
                        // 将被点击的删除按钮所在的那一行直接从DOM树中删掉
                        $btnEle.parent().parent().remove();
                        swal("删掉了!", "赶紧回去收拾行李吧,准备跑路!", "success");
                    }else{
                        swal('发生了未知的错误','估计是有bug了','info')
                    }
                }
            });

        });
    })
</script>
</body>
</html>
前端

六:自定义分页器

复制代码
class Pagination(object):
    def __init__(self,current_page,all_count,per_page_num=2,pager_count=11):
        """
        封装分页相关数据
        :param current_page: 当前页
        :param all_count:    数据库中的数据总条数
        :param per_page_num: 每页显示的数据条数
        :param pager_count:  最多显示的页码个数
        
        用法:
        queryset = model.objects.all()
        page_obj = Pagination(current_page,all_count)
        page_data = queryset[page_obj.start:page_obj.end]
        获取数据用page_data而不再使用原始的queryset
        获取前端分页样式用page_obj.page_html
        """
        try:
            current_page = int(current_page)
        except Exception as e:
            current_page = 1

        if current_page <1:
            current_page = 1

        self.current_page = current_page

        self.all_count = all_count
        self.per_page_num = per_page_num


        # 总页码
        all_pager, tmp = divmod(all_count, per_page_num)
        if tmp:
            all_pager += 1
        self.all_pager = all_pager

        self.pager_count = pager_count
        self.pager_count_half = int((pager_count - 1) / 2)

    @property
    def start(self):
        return (self.current_page - 1) * self.per_page_num

    @property
    def end(self):
        return self.current_page * self.per_page_num

    def page_html(self):
        # 如果总页码 < 11个:
        if self.all_pager <= self.pager_count:
            pager_start = 1
            pager_end = self.all_pager + 1
        # 总页码  > 11
        else:
            # 当前页如果<=页面上最多显示11/2个页码
            if self.current_page <= self.pager_count_half:
                pager_start = 1
                pager_end = self.pager_count + 1

            # 当前页大于5
            else:
                # 页码翻到最后
                if (self.current_page + self.pager_count_half) > self.all_pager:
                    pager_end = self.all_pager + 1
                    pager_start = self.all_pager - self.pager_count + 1
                else:
                    pager_start = self.current_page - self.pager_count_half
                    pager_end = self.current_page + self.pager_count_half + 1

        page_html_list = []
        # 添加前面的nav和ul标签
        page_html_list.append('''
                    <nav aria-label='Page navigation>'
                    <ul class='pagination'>
                ''')
        first_page = '<li><a href="?page=%s">首页</a></li>' % (1)
        page_html_list.append(first_page)

        if self.current_page <= 1:
            prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
        else:
            prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)

        page_html_list.append(prev_page)

        for i in range(pager_start, pager_end):
            if i == self.current_page:
                temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)
            else:
                temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)
            page_html_list.append(temp)

        if self.current_page >= self.all_pager:
            next_page = '<li class="disabled"><a href="#">下一页</a></li>'
        else:
            next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)
        page_html_list.append(next_page)

        last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
        page_html_list.append(last_page)
        # 尾部添加标签
        page_html_list.append('''
                                           </nav>
                                           </ul>
                                       ''')
        return ''.join(page_html_list)
分页器代码

相关推荐