Django之Ajax相关

Ajax介绍

Ajax:异步提交,局部刷新
发送请求:
	1.浏览器输入网址
	2.form表单
	3.a标签
	4.ajax  ===> POST/GET
Ajax:
	1.并不是一门新的编程语言,而是一门新的标准方法(类似于装饰器)
	2.能够在不刷新页面的前提下,与服务器交换数据刷新部分内容

Ajax基本格式

前端基本格式
 $('.btn').click(function () {
        $.ajax({
            // 1.指定朝那个后端发数据
            url: '',
            // 2.请求方式
            type: 'post',
            // 补充1
  			dataType:'post' // 针对后端httpresponse发送过来的数据自动反序列化
            // 3.发送的数据
            data: {'d1': $('#d1').val(), 'd2': $('#d2').val()},
            // 4.回调函数:当后端给你返回结果的时候会自动触发 args接受后端的返回结果
            success: function (args) {
                let dict = JSON.parse(args)
                alert(dict)
                $('#d3').val(dict.d3)
                console.log(typeof (dict))
            }
        })
    })
后端处理:
    if request.method == 'POST':
        d1 = request.POST.get('d1')
        print(d1)
        d2 = request.POST.get('d2')
        d3 = int(d1) + int(d2)
        d3_dict = {'d3': d3}
        return HttpResponse(json.dumps(d3_dict)) # 非自动转化,后端dumps操作,前端反序列化操作parse()
        # return JsonResponse(d3_dict) 自动转化格式,在模板语法中直接就是反序列过的
        

前后端传输数据基本文件格式(ContentType)

1.get/post请求的差别
get请求的数据放在网址的/?后面进行字符串拼接传给后端
post请求的数据会放在请求体中传给后端
2.前后端交互的三种文件格式
针对form表单
	urlencoded
		默认的传输格式
		无论是在请求体和请求头数据格式都是类似:username=123&passowrd=456
		后端针对拿到符合urlencoded的数据格式会自动处理后封装到request.POST对象中
	formdata
		formdata支持文件和数据的传输
		会自动去问文件和数据,将符合urlencoded的数据放到request.POST对象中
		文件格式会放到FILES中
	json
针对ajax
	默认也是urlencoded传输
	数据格式也是类似:username=123&passowrd=456
	将符合urlencoded的数据格式处理后封装到request对象之中

ajax发送json数据

1.request对象补充.
	request.is_ajax()
	用来判断当前发送请求的方式是否为ajax
	是:True 否:False
2.ajax发送json数据参数
contentType:'application/json'
如果要发送json格式的数据,必须要保证发送的数据和指定的数据类型一致
3.ajax发送的json数据存储在request.body中
所有要在body中获取
<script>
    $('#d1').click(function () {
        $.ajax({
            url:'',
            type:'post',
            data:JSON.stringify({'username':'jason','age':25}),
            contentType:'application/json',  // 指定编码格式
            success:function () {

            }
        })
    })
</script>

        json_bytes = request.body
        json_str = json_bytes.decode('utf-8')
        json_dict = json.loads(json_str)

        # json.loads括号内如果传入了一个二进制格式的数据那么内部自动解码再反序列化
        json_dict = json.loads(json_bytes)

ajax发送文件数据

1.ajax发送文件数据需要借用js内置对象FormData
2.即可以接受文件数据,也可以皆有urlencoded格式的数据
3.发送文件必须指定两个参数
	1.contentType:'false' //不需要使用任何编码格式,django后端会自动识别
	2.processType:'false  //告诉浏览器不要对数据进行任何加工
<body>
    username:<input  name='user' type="text" id="d1">
    password:<input type="text" name="password" id="d2">
    <input type="file" name="file" id="d3">
    <button id="d4">提交ajax</button>
    <script>
        $('#d4').on('click',function (){
            // 1.创造FormData对象
            let formDateObj = new FormData();
            // 2.添加键值对
            formDateObj.append('username', $('#d1').val());
            formDateObj.append('password', $('#d2').val());
            // 3.添加文件对象
            formDateObj.append('file', $('#d3')[0].files[0]);
            // 4.ajax请求 
            $.ajax(
                {
                    url:'',
                    type:'post',
                    data:formDateObj,
                    contentType:false,
                    processData:false,
                    success:function (arg){

                    }
                }

            )
        })
    </script>
def ab_file(request):
    if request.is_ajax():
        if request.method == 'POST':
            print(request.POST)
            print(request.FILES)
    return render(request, 'ab_file.html')

django自带的序列化组件

针对前后端分离的开发项目,后端一般只要返回列表套字典的数据格式给前端就可,不需要进一步进行前端操作
from djaong.core import serializers
def ab_ser(request):
    user_queryset = models.User.objects.all()
    // 也可以手动操作 
   	'''
   	user_list = []
   	for user_obj in user_queryset:
   		user = {name:'...',.......}
		user_list.append(user)
   	'''
    res = serializers.serialize('json',user_queryset) // 自动转化为序列化的json格式
     return HttpResponse(res)

批量插入数据

1.for循环

2.bulk_create() 速度快,能够大大减少数据插入的时间
1.for
...
2.bulk_create()
def ab_res(request):
    book_list = []
    for i in range(1000):
        book_obj = models.MySqlite(name='第%s本' % (i+1))
        book_list.append(book_obj)
    models.MySqlite.objects.bulk_create(book_list)
    obj = models.MySqlite.objects.all()
    return render(request, 'ab_res.html', locals())

ajax结合sweetlet二次删除确认

1.在前端书写代码,并且绑定button,可以将关键数据存入到按钮的attr中,方便拿取
	传数据的两种方式:
		1.通过data在请求体中传入的ID值
			#{url:'/delete/user/' + currentBtn.attr('delete_id'),  // 1 传递主键值方式1#}
		2.直接在url使用反向解析拿到传入的ID值
		     # data:{'delete_id':currentBtn.attr('author_id')},
2.将要处理的数据传入后端进行操作,后端返回状态码已经信息
3.前端接受并根据状态码进行回调函数触发提醒框操作
模板使用
<script>
    $('.del').on('click',function () {
        // 先将当前标签对象存储起来
        let currentBtn = $(this);
        // 二次确认弹框
        swal({
          title: "你确定要删吗?",
          text: "你可要考虑清除哦,可能需要拎包跑路哦!",
          type: "warning",
          showCancelButton: true,// 取消按钮
          confirmButtonClass: "btn-danger", // 确认按钮格式
          confirmButtonText: "是的,老子就要删!", // 确认按钮文本内容
          cancelButtonText: "算了,算了!", // 取消按钮文本内容
          closeOnConfirm:false, // 显示点击确认按钮后的swal动画
          closeOnCancel: false, // 显示点击取消按钮的swal之后的动画,
          showLoaderOnConfirm: true //显示加载界面
        },
        function(isConfirm) {
          if (isConfirm) {
                // 朝后端发送ajax请求删除数据之后 再弹下面的提示框
                $.ajax({
                    {#url:'/delete/user/' + currentBtn.attr('delete_id'),  // 1 传递主键值方式1#}
                    url:'/book_list/',  // 2 放在请求体里面
                    type:'post',
                    data:{'delete_id':currentBtn.attr('author_id')},
                    success:function (args) {  // args = {'code':'','msg':''}
                        // 判断响应状态码 然后做不同的处理
                        console.log(typeof(args))
                        if(args.code === 1000){
                            swal("\r\n", args.msg, "success");
                            // 1.lowb版本 直接刷新当前页面
                            {#window.location.reload()#}
                            // 2.利用DOM操作 动态刷新
                            currentBtn.parent().parent().remove()
                        }else{
                            swal('error!','出现未知错误','error')
                        }
                    }

                })

          } else {
            swal("False", "已取消", "error");
          }
        });
    })

</script>

ajax自定义分页器推导

1.后端
    # 1.先拿到作者对象
    author_objs = models.Author.objects.all()
    # 2.拿到用户发请求的页数
    current_page = request.GET.get('page', 1)  # 如果没有拿到数据就默认返回1
    count_page = author_objs.count()
    # 3.计算总页数
    div_page, more = divmod(count_page, 10)
    if more:
        div_page += 1
    try:
        current_page = int(current_page)
    except Exception:
        current_page = 1
    if current_page > div_page:
        current_page = 1
    # 4.根据用户发过来的页数计算每页显示的数据
    page_number = 10
    start_page = (current_page - 1) * page_number
    end_page = current_page * page_number
    # 4.分页器制作
    # 4.1如果分页器默认小于6就让判断条件为6,如果大于了最高的页数就让他默认为倒数第五页
    page_html = ''
    xxx = current_page
    if current_page < 6:
        current_page = 6
    if current_page >= div_page - 5:
        current_page = div_page - 5
    for i in range(current_page - 5, current_page + 6):
        if i == xxx:
            page_html += '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i)
        else:
            page_html += '<li class=""><a href="?page=%s">%s</a></li>' % (i, i)
    data_queryset = author_objs[start_page:end_page]
    # 5.返回显示的数据
    return render(request, 'ab_fy.html', locals())

<!--前端-->
<body>
    {% for data in data_queryset %}
    <p>{{ data.name }}</p>
    {% endfor %}
<nav aria-label="Page navigation">
  <ul class="pagination">
    <li>
      <a href="#" aria-label="Previous">
        <span aria-hidden="true">&laquo;</span>
      </a>
    </li>
      {{ page_html|safe }}
    <li>
      <a href="#" aria-label="Next">
        <span aria-hidden="true">&raquo;</span>
      </a>
    </li>
  </ul>
</nav>
</body>

自定义分页器的使用

自定义工具的使用

当需要使用非django第三方组件以及自己写的第三方代码时
通常会咋子应用下或者django项目下创建一个utils文件夹
并且在utils进行功能划分,然后将代码放入其中

自定义分页器代码

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:  最多显示的页码个数
        """
        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)

自定义分页器的使用

1.先拿到数据库中数据对象
	books_queryset = models.Book.objects.all()
2.通过前端获取当前页
	current_page = request.GET.get('page',1)
3.统计数据总数
	all_count = book_queryset.count()
4.调用类传入参数
	page_obj = pagemaker.Pagination(current_page=current_page, all_count=allcount)
5.调用对象的函数生产start和end参数拿到每页的数据
	booK_queryset = book_queryset[page_obj.start:page_obj.end]
6.直接向前端传入对象
	return render(request, 'book_list.html', locals())
接收到的数据直接渲染
由于在后端代码中已经将分页器的代码写好所以前端直接调用分页器的
{{page_obj.page_html:safe}}直接进行分页操作
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值