zoukankan      html  css  js  c++  java
  • Python自动化运维

    Ajax基础

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

      AJAX 是与服务器交换数据并更新部分网页的艺术,在不重新加载整个页面的情况下。

    什么是Ajax

      AJAX = 异步 JavaScript 和 XML,是一种用于创建快速动态网页的技术。

      通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新,传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。

          概括:AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。

    使用ajax

      我们在运维开发过程中用到的ajax基本都是jquery提供的,因为jquery封装的简单易懂,用起来比原生的要方便很多,节省了大量的学习成本,这里将以jquery提供的ajax来做实例说明。(依赖XMLHttprequest对象,这里不再详细说明)

    语法

    jQuery.ajax([settings])    # 方式一
    $.ajax([settings])         # 方式二
    

    PS:因为jQuery可以用$,进行表示,所以一般常用的就是$.ajax()

    参数 

     ajax提供了很多参数,在提交的时候可以进行选择,这里settings表示一个参数字典。常用的参数如下:

    • url:表示要提交到的url地址
    • type:表示以什么方式提交
    • data:表示要提交什么数据,可以是一个字典,用于存放要提交的name和value
    • dataType:表示接受数据库的类型,一般为JSON,当指定该参数值为JSON时,那么success函数的参数data,就会被jquery转正json对象(不用再调用json来转换了 )
    • traditional:告诉jquery阻止深度序列化,默认情况下为false会深度序列化这个对象,以适应PHP等框架,我们可以通过设置tradtional为true,这样传递checkbox的多选的情况下(列表、数组等),才可以正常传输到后端。
    • success:值为函数对象,执行成功后,会自动执行该函数。(必须要有参数,表示执行成功后,服务端返回的data)
    <script>
    $('.submit').click(function (){
        $.ajax({
            url:'/test',
            type:'post',
            data:{'user':'root','password':'123456'},
            success:function (data){       // data是服务器端返回的字符串,所以django需要使用Httpresponse进行返回(其实render也可以但是前端json反序列化就会出问题,但是redirect是不行的)
    if (data == 'ok') { location.reload() // 成功重新加载页面 }else { alert(data) // 否则就弹出告警信息 } } }) }) </script>

    jQuery还封装的有其他方法比如:$.get,$.post等,他们内部调用的都是$.ajax(),需要注意的是,传递的参数不同,直接像函数传参一样,传递即可,不用是字典类型

    $.post(url='xxx',data={xxx},...)
    

    PS:data参数在这里需要注意的是,如果我们要提交的是某个form下的数据,那么我们一个一个取就比较麻烦了,这时可以找到form通过serialize()来获取form中的所有数据组成name,value对,进行提交。

    注意 

    使用ajax提交,大部分场景下都是对用户提交的数据进行验证,这里要说的是如何使django返回一个信息或者说进行一个处理。

    1. 定义一个用户返回的字典,比如:ret_data = {'status':null,'data':'xxx','error':'xxx'}
    2. 当出现异常或者用户提交的数据不匹配时,可以对该字典的status,error进行修改
    3. 最后把字典,json序列化后返回给ajax
    4. ajax的函数,对服务端返回的data,反序列化后进行解析,根据不同的status或者code来定义不同的操作(javascript反序列化,json.parse(data),序列化用 json.stringfy('abc'))

    ajax异常处理

    ajax参数中还有个error对应一个函数,用来进行异常处理。 简单的说Ajax请求通过XMLHttpRequest对象发送请求,该对象有四个状态(readyState):

    0 - (未初始化)  # 还没有调用send()方法
    1 - (载入)     # 已调用send()方法,正在发送请求
    2 - (载入完成)  # send()方法执行完成,已经接收到全部响应内容
    3 - (交互)     # 正在解析响应内容
    4 - (完成)     # 响应内容解析完成,可以在客户端调用了 

    当XMLHttpRequest.readyState为4时,表示ajax请求已经完成可以得到响应结果。

    ajax的success和error方法根据响应状态码来触发。当XMLHttpRequest.status为200的时候,表示响应成功,此时触发success().其他状态码则触发error()。

    除了根据响应状态码外,ajax还会在下列情况下走error方法:

    1. 返回数据类型不是JSON
    2. 网络中断
    3. 后台响应中断
    # error函数语法为:
    
    # (默 认: 自动判断 (xml 或 html)) 请求失败时调用时间。
    # 参数有以下三个:XMLHttpRequest 对象、错误信息、(可选)捕获的错误对象。
    # 如果发生了错误,错误信息(第二个参数)除了得到null之外,
    # 还可能是"timeout", "error", "notmodified" 和 "parsererror"。
      
    # textStatus: "timeout", "error", "notmodified" 和 "parsererror"。
     
    error:function (XMLHttpRequest, textStatus, errorThrown) 
    { 
        ''' javascript code '''  
    } 
    

    定制ajax

      类似于公共配置的含义,我们可以利用ajaxsetup,对当前页面中的所有ajax请求,进行统一配置。其中一个常用的配置为beforeSend,用于在ajax提交时先执行的函数,它的值是一个函数。

    $.ajaxsetup({
        beforeSend:function (xhr,setting) {
            xhr.setRequestHeader('key','value)
        }
    })
    

    PS:这里的xhr就是前面所说的XMLHttpRequest对象,利用它的setRequestHearder方法来为所有的ajax请求添加请求头。

    自定义分页 

       当要显示的数据量很多,超过了一页时,就需要进行分页显示,这里的自定义分页,是独立于django框架的,并且这里的逻辑在任何语言中都适用。

    由前端对页码进行处理

    # --------------------  views.py  --------------------
    
    def page(request):
    
        if request.method == 'GET':
    
            start_page = int(request.GET.get('page',1))  # 获取页面,如果没有传递页码,默认显示第一页
            start = ( start_page - 1 )* 10               # 获取起始页,每页显示10个元素
            end = start_page * 10                        # 计算结束页
            all_data = [ i for i in range(107)]          # 模拟总数据条数
            data = all_data[start:end]                   # 根据起始页和结束页,对数据进行过滤
            counts = len(all_data)               # 获取总数据条目数
            count,y = divmod(counts,10)             # 计算分页数
            if y:
                count += 1                     # 余数不为0,则页码数加一
    
            page_count = [ data for data in range(1,count+1)]   # 由于jinja2不能使用 类C式的循环,那么这里进行生成
    
        return render(request,'page.html',{'data':data,'page_count':page_count,'current_page':start_page})
    
     1 # -------------------- page.html --------------------
     2 <!DOCTYPE html>
     3 <html lang="en">
     4 <head>
     5     <meta charset="UTF-8">
     6     <title>Title</title>
     7     <style>
     8         .page {
     9             text-decoration: none;
    10             margin-right: 3px;
    11         }
    12 
    13         .active {
    14             background-color: saddlebrown;
    15             color: white;
    16         }
    17     </style>
    18 </head>
    19 <body>
    20 <!-- 模拟数据显示 -->
    21 <ul>
    22     {% for item in data %}
    23         <li>{{ item }}</li>
    24     {% endfor %}
    25 </ul>
    26 
    27 <!-- 页码显示 -->
    28 {% for foo in page_count %}
    29     {% if foo == current_page %}     <!-- 如果是当前页码,则进行热点显示 -->
    30         <a href="/page/?page={{ foo }}" class="page active">{{ foo }}</a>
    31     {% else %}
    32         <a href="/page/?page={{ foo }}" class="page">{{ foo }}</a>
    33     {% endif %}
    34 {% endfor %}
    35 
    36 </body>
    37 </html>
    page.html

    后端生成html代码进行页码处理

      页码由后端进行生成后,传递给前端直接显示,这样可定制性更强,但是增加了代码的耦合度。

    # -------------------- views.py --------------------
    def page(request):
    
        if request.method == 'GET':
    
            current_page = int(request.GET.get('page',1))  # 获取页面,如果没有传递页码,默认显示第一页
            start = ( current_page - 1 )* 10               # 获取起始页,每页显示10个元素
            end = current_page * 10                        # 计算结束页
            all_data = [ i for i in range(107)]            # 模拟总数据条数
            data = all_data[start:end]                     # 根据起始页和结束页,对数据进行过滤
            counts = len(all_data)                         # 获取总数据条目数
            count,y = divmod(counts,10)                    # 计算分页数
            if y:
                count += 1                                 # 余数不为0,则页码数加一
    
            temp_list = []                                 # 要返回给前端页面的html组成的列表
            for i in range(1,count+1):
                if i == current_page:                      # 对当先显示的页码进行特殊处理
                    temp = "<a href= '/page/?page={0}' class='page active' >{0}</a>".format(i)
                else:
                    temp = "<a href= '/page/?page={0}' class='page' >{0}</a>".format(i)
                temp_list.append(temp)
    
            temp_list=''.join(temp_list)
    
        return render(request,'page.html',{'data':data,'current_page':current_page,'temp_list':temp_list})
    
     1 # -------------------- page.html --------------------
     2 <!DOCTYPE html>
     3 <html lang="en">
     4 <head>
     5     <meta charset="UTF-8">
     6     <title>Title</title>
     7     <style>
     8         .page {
     9             text-decoration: none;
    10             margin-right: 3px;
    11         }
    12 
    13         .active {
    14             background-color: saddlebrown;
    15             color: white;
    16         }
    17     </style>
    18 </head>
    19 <body>
    20 <!-- 模拟数据显示 -->
    21 <ul>
    22     {% for item in data %}
    23         <li>{{ item }}</li>
    24     {% endfor %}
    25 </ul>
    26 
    27 <!-- 页码显示 -->
    28 {{ temp_list | safe }}
    29 
    30 </body>
    31 </html>
    page.html

    PS:由于为了防止XSS攻击,默认后端传过来的html,页面是不会渲染的,会当成字符串直接打印,所以,这里使用了模板提供的过滤器 safe ,用来标识后端传递的代码是安全的,这样html就可以进行渲染了,当然还有第二种方法,在后端利用make_safe进行安全格式化。

    from django.utils.safestring import mark_safe
    temp_list = mark_safe(temp_list)
    
    # 利用mark_safe 安全格式化html
    # 前端直接进行渲染即可
    

    优化页码显示

    1. 抽出可能变化的量,比如每页显示的数据量,显示的页码量
    2. 当前页码小于1时优化,当前页码大于最大页码时优化
    3. 上一页、下一页功能
    4. 针对页码量的优化
    all_data = [i for i in range(1007)]  # 模拟总数据条数
    
    def page(request):
    
        if request.method == 'GET':
    
            per_page_count = 10   # 每页显示的数量
            pager_num = 11        # 一共显示多少个页码
    
            current_page = int(request.GET.get('page',1))  # 获取页面,如果没有传递页码,默认显示第一页
            start = ( current_page - 1 )* per_page_count   # 获取起始页,每页显示10个元素
            end = current_page * per_page_count    # 计算结束页
    
            data = all_data[start:end]   # 根据起始页和结束页,对数据进行过滤
            counts = len(all_data)       # 获取总数据条目数
            total_count,y = divmod(counts,per_page_count)   # 计算分页数
            if y:
                total_count += 1   # 余数不为0,则页码数加一
    
            # 页码处理
            if total_count < pager_num :   # 总页数小于11页,就定死显示1-11页码
                start_index = 1
                end_index = pager_num
            else:
                if current_page <= 6:      # 当前页小于6时,就定死显示1-11页码
                    start_index = 1
                    end_index = pager_num
                else:        # 动态的显示pager_name个页码
                    start_index = current_page - int((pager_num / 2))
                    end_index = current_page + int((pager_num / 2))
                    if current_page + int((pager_num / 2)) >= total_count:   # 当前页码的最大区间超过了总页码,就固定显示,最后的11个页码
                        start_index = total_count - per_page_count
                        end_index = total_count
    
            # 上一页
            if current_page - 1 <= 0 :     # 如果当前页为1,那么就禁止使用上一页
                per_html = "<a href= '#' class='page' >上一页</a>"
            else:
                per_html = "<a href= '/page/?page={0}' class='page' >上一页</a>".format(current_page-1)
    
            temp_list = []        # 要返回给前端页面的html组成的列表
    
            temp_list.append(per_html)
            for i in range(start_index,end_index+1):
                if i == current_page:    # 对当先显示的页码进行特殊处理
                    temp = "<a href= '/page/?page={0}' class='page active' >{0}</a>".format(i)
                else:
                    temp = "<a href= '/page/?page={0}' class='page' >{0}</a>".format(i)
                temp_list.append(temp)
    
            # 下一页
            if current_page + 1 > total_count:    # 如果当前页大于总页数,仅用下一页
                after_html = "<a href= '#' class='page' >下一页</a>"
            else:
                after_html = "<a href= '/page/?page={0}' class='page' >下一页</a>".format(current_page + 1)
            temp_list.append(after_html)
    
            temp_list=''.join(temp_list)
    
        return render(request,'page.html',{'data':data,'current_page':current_page,'temp_list':temp_list})
    

    封装

      由于分页功能在许多地方都会使用,如果每个地方都写这么长的代码,那么会非常麻烦,这里对分页功能进行封装。

      在项目目录下创建utils目录用于存放模块/类文件。

    #!/usr/bin/env python
    # _*_coding:utf-8_*_
    # __time__: 2018/3/13 00:02
    # __author__: daxin
    # __file__: pagination.py
    
    
    class Page(object):
    
        def __init__(self,current_page,counts,per_page_count=10,pager_num=11):
            self.current_page = current_page
            self.counts = counts
            self.per_page_count = per_page_count
            self.pager_num = pager_num
    
        @property
        def start(self):    # 获取起始索引
            return ( self.current_page - 1 )* self.per_page_count
    
        @property
        def end(self):      # 获取结束索引
            return self.current_page * self.per_page_count
    
        @property
        def total_count(self):    # 计算总页码
            total_count, y = divmod(self.counts, self.per_page_count)  # 计算分页数
            if y:
                total_count += 1  # 余数不为0,则页码数加一
    
            return total_count
    
    
        def page_str(self,base_dir):    # 传递url,可以配合不同的url生成页码
            # 页码处理
            if self.total_count < self.pager_num:  # 总页数小于11页,就定死显示1-11页码
                start_index = 1
                end_index = self.pager_num
            else:
                if self.current_page <= 6:  # 当前页小于6时,就定死显示1-11页码
                    start_index = 1
                    end_index = self.pager_num
                else:  # 动态的显示pager_name个页码
                    start_index = self.current_page - int((self.pager_num / 2))
                    end_index = self.current_page + int((self.pager_num / 2))
                    if self.current_page + int((self.pager_num / 2)) >= self.total_count:  # 当前页码的最大区间超过了总页码,就固定显示,最后的11个页码
                        start_index = self.total_count - self.pager_num + 1
                        end_index = self.total_count
    
            # 上一页
            if self.current_page - 1 <= 0:  # 如果当前页为1,那么就禁止使用上一页
                per_html = "<a href= '#' class='page' >上一页</a>"
            else:
                per_html = "<a href= '{1}?page={0}' class='page' >上一页</a>".format(self.current_page - 1,base_dir)
    
            temp_list = []  # 要返回给前端页面的html组成的列表
    
            temp_list.append(per_html)
            for i in range(start_index, end_index + 1):
                if i == self.current_page:  # 对当先显示的页码进行特殊处理
                    temp = "<a href= '{1}?page={0}' class='page active' >{0}</a>".format(i,base_dir)
                else:
                    temp = "<a href= '{1}?page={0}' class='page' >{0}</a>".format(i,base_dir)
                temp_list.append(temp)
    
            # 下一页
            if self.current_page + 1 > self.total_count:  # 如果当前页大于总页数,仅用下一页
                after_html = "<a href= '#' class='page' >下一页</a>"
            else:
                after_html = "<a href= '{1}?page={0}' class='page' >下一页</a>".format(self.current_page + 1,base_dir)
            temp_list.append(after_html)
    
            temp_list = ''.join(temp_list)
            return temp_list
    

      在views中倒入我们封装好的分页文件pagination文件即可。

    from utils import pagination     # 倒入我们写好的分页模块文件
    
    def page(request):
    
        if request.method == 'GET':
    
            current_page = int(request.GET.get('page',1))
            counts = len(all_data)
            page_obj = pagination.Page(current_page,counts)
            data = all_data[page_obj.start:page_obj.end]
            temp_list =page_obj.page_str('/page/')    # 传递url
    
        return render(request,'page.html',{'data':data,'current_page':current_page,'temp_list':temp_list})
    

    PS:这样我们的分页就封装完毕了,在其他地方需要使用的时候,可以直接调用pagination文件,引入Page类即可。  

  • 相关阅读:
    定时器
    按键中断部分的理解
    初中数学
    WING IDE 快捷键
    机器学习各种网址
    SQL With As 用法Sql 四大排名函数(ROW_NUMBER、RANK、DENSE_RANK、NTILE)简介
    Python编码格式导致的csv读取错误
    Oracle中的rownum 和rowid的用法和区别
    oracle配置
    matplotlib命令与格式:标题(title),标注(annotate),文字说明(text)
  • 原文地址:https://www.cnblogs.com/dachenzi/p/8493741.html
Copyright © 2011-2022 走看看