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})
 # -------------------- page.html --------------------
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.page {
text-decoration: none;
margin-right: 3px;
} .active {
background-color: saddlebrown;
color: white;
}
</style>
</head>
<body>
<!-- 模拟数据显示 -->
<ul>
{% for item in data %}
<li>{{ item }}</li>
{% endfor %}
</ul> <!-- 页码显示 -->
{% for foo in page_count %}
{% if foo == current_page %} <!-- 如果是当前页码,则进行热点显示 -->
<a href="/page/?page={{ foo }}" class="page active">{{ foo }}</a>
{% else %}
<a href="/page/?page={{ foo }}" class="page">{{ foo }}</a>
{% endif %}
{% endfor %} </body>
</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})
 # -------------------- page.html --------------------
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.page {
text-decoration: none;
margin-right: 3px;
} .active {
background-color: saddlebrown;
color: white;
}
</style>
</head>
<body>
<!-- 模拟数据显示 -->
<ul>
{% for item in data %}
<li>{{ item }}</li>
{% endfor %}
</ul> <!-- 页码显示 -->
{{ temp_list | safe }} </body>
</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类即可。 

Python自动化运维 - Django(二)Ajax基础 - 自定义分页的更多相关文章

  1. Python自动化运维 - Django(三)CSRF - Cookie&Session

    CSRF跨站请求伪造 CSRF跨站点请求伪造(Cross—Site Request Forgery),跟XSS攻击一样,存在巨大的危害性,你可以这样来理解:攻击者盗用了你的身份,以你的名义发送恶意请求 ...

  2. 【目录】Python自动化运维

    目录:Python自动化运维笔记 Python自动化运维 - day2 - 数据类型 Python自动化运维 - day3 - 函数part1 Python自动化运维 - day4 - 函数Part2 ...

  3. Python自动化运维 技术与最佳实践PDF高清完整版免费下载|百度云盘|Python基础教程免费电子书

    点击获取提取码:7bl4 一.内容简介 <python自动化运维:技术与最佳实践>一书在中国运维领域将有"划时代"的重要意义:一方面,这是国内第一本从纵.深和实践角度探 ...

  4. Python自动化运维:技术与最佳实践 PDF高清完整版|网盘下载内附地址提取码|

    内容简介: <Python自动化运维:技术与最佳实践>一书在中国运维领域将有“划时代”的重要意义:一方面,这是国内第一本从纵.深和实践角度探讨Python在运维领域应用的著作:一方面本书的 ...

  5. python自动化运维篇

    1-1 Python运维-课程简介及基础 1-2 Python运维-自动化运维脚本编写 2-1 Python自动化运维-Ansible教程-Ansible介绍 2-2 Python自动化运维-Ansi ...

  6. Python自动化运维的职业发展道路(暂定)

    Python职业发展之路 Python自动化运维工程 Python基础 Linux Shell Fabric Ansible Playbook Zabbix Saltstack Puppet Dock ...

  7. python自动化运维之CMDB篇-大米哥

    python自动化运维之CMDB篇 视频地址:复制这段内容后打开百度网盘手机App,操作更方便哦 链接:https://pan.baidu.com/s/1Oj_sglTi2P1CMjfMkYKwCQ  ...

  8. Day1 老男孩python自动化运维课程学习笔记

    2017年1月7日老男孩python自动化运维课程正式开课 第一天学习内容: 上午 1.python语言的基本介绍 python语言是一门解释型的语言,与1989年的圣诞节期间,吉多·范罗苏姆为了在阿 ...

  9. python自动化运维学习第一天--day1

    学习python自动化运维第一天自己总结的作业 所使用到知识:json模块,用于数据转化sys.exit 用于中断循环退出程序字符串格式化.format字典.文件打开读写with open(file, ...

随机推荐

  1. java List接口实现类

    首先看这两类都实现List接口,而List接口一共有三个实现类,分别是ArrayList.Vector和LinkedList.List用于存放多个元素,能够维护元素的次序,并且允许元素的重复.3个具体 ...

  2. DELPHI BOOKMARK使用

    关于书签(BookMark)操作:       书签操作主要用于在表中快速地定位记录指针,在应用程序中常常要保存记录指针所在的位置,在进行其他处理之后,希望能快速地返回到先前指针所在的位置,此时,使用 ...

  3. Java的第一个程序-Hello, World !

    学了一个月的Java,现在总结一下,就算复习了. 一.安装Java环境 这个没啥好说的. 1. 官网下载JDK安装 2. 配置环境变量.注意的是:环境变量配置好以后,如果cmd中运行 java 命令没 ...

  4. bzoj 1934: [Shoi2007]Vote 善意的投票 (最小割)

    原来是赞同的连源,原来是反对的连汇,然后是朋友的就连在一起,这样最小割就是割掉违背和谐的吧 type arr=record toward,next,cap:longint; end; const ma ...

  5. BZOJ3224:普通平衡树——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=3224 题面源于洛谷 题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下 ...

  6. 使用C#解析并运行JavaScript代码

    如果想在C#编程中解析并运行JavaScript代码,常见的方式有两种: 利用COM组件“Microsoft Script Control”,可参见:C#使用技巧之调用JS脚本方法一 利用JScrip ...

  7. 【计数原理】【UVA11538】 Chess Queen

    传送门 Description 给你一个n*m的棋盘,在棋盘上放置一黑一白两个皇后,求两个皇后能够互相攻击的方案个数 Input 多组数据,每组数据包括: 一行,为n和m 输入结束标志为n=m=0. ...

  8. BUG:Open quote is expected for attribute "{1}" associated with an element type "id".

    BUG原因:Mybatis的xml文件中id缺少双引号: 正确的应该是:

  9. How to configue session timeout in Hive

    This article explains how to configure the following settings in Hive:hive.server2.session.check.int ...

  10. beego入门小坑

    刚接触beego,按照官网的文档操作,始终发现在orm操作数据的时候提示表不存在,数据库连接设置都没问题 "0 Error 1146: Table 'beego.archives' does ...