Ajax

目录

Ajax知识准备Json

什么是Json

JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)

JSON 是轻量级的文本数据交换格式

Ajax

stringify与parse方法

JavaScript中关于JSON对象和字符串转换的两个方法:

JSON.parse(): 用于将一个 JSON 字符串转换为 JavaScript 对象

JSON.parse('{"name":"Howker"}');
JSON.parse('{name:"Stack"}') ;   // 错误
JSON.parse('[18,undefined]') ;   // 错误

JSON.stringify(): 用于将 JavaScript 值转换为 JSON 字符串

JSON.stringify({"name":"Tonny"})

Ajax简介

Ajax,全称为Asynchronous JavaScript and XML,即异步的JavaScript和XML。

它不是一门编程语言,

而是利用JavaScript在保证页面不被刷新、页面链接不改变 的 情况下与服务器交换数据 并更新部分网页的技术

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

Ajax异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。非阻塞,通过异步回调机制 callback()返回结果

与后端进行交互的方式:

浏览器地址栏输入url: GET

a标签href:GET/POST

form表单:GET/POST

Ajax: GET/POST

初始Ajax

案例:页面有三个input框,一个按钮

用户在前两个框中输入数字,点击按钮保证页面不刷新的情况下将数据发到后端做计算

将计算好的结果再发给前端展示到第三个input框中,基于jQuery封装的Ajax

index.html

<input type="text" id="i1"> + <input type="text" id="i2"> = <input type="text" id="i3">
<button id="d1">按钮</button>

<script>
    $('#d1').click(function () {
        // 获取两个框里的内容,向后端提交异步请求
        // ajax基本语法
        $.ajax({
            // 1  向哪个后盾提交数据
            url: '',
            // 2  指定提交当前请求的方式
            type: 'post',
            // 3  提交的数据
            data: {'i1':$('#i1').val(), 'i2':$('#i2').val()},
            // 4  ajax是异步提交,所以需要给一个回调函数来处理返回结果
            success: function (data) {  // data就是异步提交的返回结果
                // 将异步回调的结果通过DOM操作渲染到第三个input框中
                $('#i3').val(data)
            }
        })
    })
</script>

views.py

def index(request):
    if request.method == 'POST':
        i1 = request.POST.get('i1')
        i2 = request.POST.get('i2')
        i3 = int(i1) + int(i2)
        return HttpResponse(i3)
    return render(request,'index.html')

urls.py

from django.conf.urls import url
from app01 import views

urlpatterns = [
    url(r'^index/', views.index)
]

Ajax

Ajax常见应用常见

搜索引擎根据用户输入关键字,自动提示检索关键字

还有一个很重要的应用场景就是注册时候的用户名的查重

其实这里就使用了AJAX技术!当文件框发生了输入变化时,使用AJAX技术向服务器发送一个请求,然后服务器会把查询到的结果响应给浏览器,最后再把后端返回的结果展示出来

整个过程中页面没有刷新,只是局部刷新了;

在请求发出后,浏览器不用等待服务器响应结果就可以进行其他操作

Ajax优缺点

  • AJAX使用JavaScript技术向服务器发送异步请求;
  • AJAX请求无须刷新整个页面;
  • 因为服务器响应内容不再是整个页面,而是页面中的部分内容,所以AJAX性能高;
  • 两个关键点:1.局部刷新,2.异步请求

$.ajax()方法参数

url:

要求为String类型的参数,(默认为当前页地址)发送请求的地址。

type:

要求为String类型的参数,请求方式(post或get)默认为get。注意其他http请求方法,例如put和delete也可以使用,但仅部分浏览器支持。

data:

要求为Object或String类型的参数,发送到服务器的数据。如果已经不是字符串,将自动转换为字符串格式。get请求中将附加在url后。防止这种自动转换,可以查看processData选项。

对象必须为key/value格式,例如{foo1:"bar1",foo2:"bar2"}转换为&foo1=bar1&foo2=bar2

如果是数组,JQuery将自动为不同值对应同一个名称。例如{foo:["bar1","bar2"]}转换为&foo=bar1&foo=bar2

success:

要求为Function类型的参数,请求成功后调用的回调函数

由服务器返回,并根据dataType参数进行处理后的数据。

success:function (data){
  //data可能是xmlDoc、jsonObj、html、text等等
}

Content-Type

content-type前后端传输数据的编码格式

urlencoded

formdata

application/json

form表单

默认是urlencoded编码格式传输数据

urlencoded数据格式

  • username=santa&password=123

  • django后端针对该格式的数据,会自动解析并帮你打包到request.POST中

formdata数据格式

  • django后端针对符合urlencoded编码格式数据(普通键值对)还是统一解析到request.POST中
  • 而针对formdata文件数据就会自动解析放到request.FILES中

ajax提交

ajax默认的也是urlencoded编码格式

前后端数据交互 编码格式与数据格式一定要一致

application/json

  • django后端针对json格式数据 并不会做任何的处理,而是直接放在request.body中

Ajax发送数据

基于Ajax发送json数据

1 指定编码格式为application/json

2 将数据序列化为json串,保证与编码格式一致(前端的序列化JSON)

3 后端处理json格式的数据,不会做任何处理,原封不动的封装到request.body中

<button id="d3">ajax发送文件数据</button>
<script>
    $('#d3').click(function () {
        $.ajax({
            url: '',
            type: 'post',
            // 修改content-type 参数
            contentType: 'application/json',
            data: JSON.stringify({'username': 'santa', 'password': '123'}), // 将数据序列化成json格式字符串
            success: function (data) {
                alert(data)
            }
        })
    })
</script>

views.py

import json
def ab_ct(request):
    if request.method == 'POST':
        print(request.body)   # b'{"username":"santa","password":"123"}'
        json_bytes = request.body
        # json_str = json_bytes.decode('utf-8')
        # json_dict = json.loads(json_str)
        # print(json_dict)   # {'username': 'santa', 'password': '123'}

        # 扩展  json.loads能够自动解码并序列化
        json_dict = json.loads(json_bytes)
        print(json_dict)  # {'username': 'santa', 'password': '123'}
    return render(request, 'ab_ct.html')

基于Ajax发送文件数据

1 借助于内置对象new FormData()

2 该对象可以携带文件数据,也可以传键值对

3 在Ajax中指定两个参数:

contentType:false 代表不使用任何编码格式,

processData:false 代表不对数据本身做任何处理,FormData()实例化的对象内部自带编码,django后端能够识别

<input type="file" name="myfile" id="i1">
<button id="d3">ajax发送文件数据</button>
<script>
    $('#d3').click(function () {
        // 1  需要先生成一个内置对象
        var myFormData = new FormData();
        // 2 传普通键值对,当普通键值对较多的时候,我们可以利用for循环来添加
        myFormData.append('username', 'santa');
        myFormData.append('password', 123);
        // 3  传文件
        myFormData.append('myfile', $('#i1')[0].files[0]);
        //  发送Ajax请求
        $.ajax({
            url: '',
            type: 'post',
            data: myFormData,
            //  发送formdata对象需要指定两个关键性的参数
            processData:false,  // 让浏览器不要对你的数据进行任何的操作
            contentType:false,  // 不要使用任何编码格式 对象formdata自带编码格式并且django能够识别该对象
            success: function (data) {
                alert(data)
            }
        })
    })
</script>

views.py

def ab_ct(request):
    if request.method == 'POST':
                print(request.FILES)   # <MultiValueDict: {'myfile': [<InMemoryUploadedFile: DJANGO点击.png (image/png)>]}>
  return render(request, 'ab_ct.html')

Django内置序列化功能(了解)

序列化目的:

将数据整合成一个大字典形式,再传给前端,方便数据的交互

一般用于前后端分离开发

drf django restframework
from app01 import models
from django.core import serializers

# 以视图函数index为例
def ab_se(request):
    user_queryset = models.Userinfo.objects.all()
    # user_list = []
    # for user_obj in user_queryset:
    #     user_list.append({
    #         'username':user_obj.username,
    #         'password':user_obj.password,
    #         'gender':user_obj.get_gender_display(),
    #     })
    # res = json.dumps(user_list)
    res = serializers.serialize('json',user_queryset)
    # return render(request,'ab_se.html',locals())
    return HttpResponse(res)
# res是一个字典套字典{{},{},{},{}...}
# 每一个数据表中的记录作为一个字典
# 前端接收到的只有所有的字典,没有最外层的字典

批量插入数据

bulk_create

def ab_bc(request):
    # 先插入1000条件数据
    # for i in range(1,1001):
    #     models.Book.objects.create(title='第%s本书'%i)
    book_list = []
    for i in range(1,10001):
        book_list.append(models.Book(title='新的%s书'%i))
        models.Book.objects.bulk_create(book_list)  # 批量插入数据的方式

        book_queryset = models.Book.objects.all()
        return render(request,'ab_bc.html',locals())

自定义分页器

分页数据是通过总数据切片而来,queryset对象支持正数索引和正向步长,不支持负数

Ajax

html

{% for book_obj in page_queryset %}
    <p>{{ book_obj.title }}</p>
{% endfor %}
{{ page_obj.page_html|safe }}

views.py

from app01 import models
from app01.utils.mypage import Pagination

def ab_bc(request):
    book_queryset = models.Book.objects.all()
    current_page = request.GET.get('page', 1)
    all_count = book_queryset.count()
    # 1 现生成一个自定义分页器类对象
    page_obj = Pagination(current_page=current_page,all_count=all_count,pager_count=9)
    # 2 针对真实的queryset数据进行切片操作
    page_queryset = book_queryset[page_obj.start:page_obj.end]
    return render(request,'ab_bc.html',locals())

mypage.py

class Pagination(object):
    def __init__(self, current_page, all_count, per_page_num=10, 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)

Ajax结合sweetalert实现删除二次确认

<script>
    $('.cancel').click(function () {
        var $aEle = $(this);
        swal({
          title: "你确定要删除吗?",
          text: "删除后数据将无法找回!",
          type: "warning",
          showCancelButton: true,
          confirmButtonClass: "btn-danger",
          confirmButtonText: "是的,我要删除",
          cancelButtonText: "算了吧,不删了",
          closeOnConfirm: false,
          closeOnCancel: false,
            showLoaderOnConfirm: true
        },
        function(isConfirm) {
            if (isConfirm) {
                $.ajax({
                    url: '',
                    type: 'post',
                    data: {'delete_id': $aEle.attr("book_obj.pk")},
                    success: function (data) {
                        if (data.code == 1000) {
                            swal("success");
                            {#window.location.reload();#}
                            $aEle.parent().parent().remove()
                        } else {
                            swal("error");
                        }
                    }
                });

            }else {
                swal ("取消删除")
          }
        });
    })
</script>

代码中的注意点:

1、给可删除的标签添加类delete,绑定事件click

2、下面是编写事件程序的注意点:

通过$(this)得到当前标签

3、要回传当前数据的id给服务器,通过设置标签自定义属性deleteId={{obj.id}}

4、通过$(this).attr(‘deleteId‘)获取要删除的数据id

5、通过DOM操作,实现局部的数据交互更新,但整个页面并不刷新

views.py

from django.http import JsonResponse
import time
def show_user(request):
    """
    前后端如果是通过ajax进行交互 那么交互的媒介一般情况下都是一个字典
    :param request:
    :return:
    """
    if request.method == 'POST':
        time.sleep(3)
        back_dic = {"code":1000,'msg':''}
        delete_id = request.POST.get('delete_id')
        models.Userinfo.objects.filter(pk=delete_id).delete()
        back_dic['msg'] = '删除成功,准备跑路!!!'
        return JsonResponse(back_dic)
    user_queryset = models.Userinfo.objects.all()
    return render(request,'show_user.html',locals())

django中如何开启事务

Django文件传输

相关推荐