这里说的数据提交,指的是,前端用户执行的操作,将这些信息提交到后台,比如,用户的登录,一般情况,要将用户名和密码提交到我们后台,我们再从后台数据库,进行数据的验证,进行一定的逻辑处理之后,再返回给前端。在这里,主要分为两种方式:
①新URL的方式:
特点是:跳转到一个独立的页面,操作数据量比较大比较方便,如:
# url部分 url(r'^sign_in/', v2.sign_in), url(r'^home/', v2.home),
# model部分 class User(models.Model): # 只创建简单的用户表 用户名唯一 username = models.CharField(max_length=32,unique=True) pwd = models.CharField(max_length=32)
<!--Template部分--> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>{{ user_msg }}</h1> <form action="/sign_in/" method="post"> {% csrf_token %} <p> <input type="text" name="username" placeholder="请输入用户名"> </p> <p> <input type="password" name="pwd" placeholder="请输入密码"> </p> <p> <input type="submit"> </p> </form> </body> </html>
# views处理部分 from django.shortcuts import render,redirect,HttpResponse from app02 import models def sign_in(request): ''' 登录 :param request: :return: ''' user_msg = None # 直接通过url提交默认时get请求 if request.method == "GET": # 登录界面 return render(request,"sign_in.html",{"user_msg":"游客"}) else: # 登录界面登录之后,通过表单的形式进行提交,也就是我们说的新URL方式 # 获取提交过来的数据 u = request.POST.get("username") p = request.POST.get("pwd") # 查询数据库,看用户名和密码是否对应的上 user = models.User.objects.filter(username=u).first() if user: # 如果用户存在,判断用户名是否存在 if user.pwd == p: return redirect("/home/") else: return render(request,"sign_in.html",{"user_msg":"密码错误"}) else: return render(request,"sign_in.html",{"user_msg":"用户不存在"}) def home(request): return render(request,"home.html")
②对话框方式,主要就是通过Ajax来提交的
特点是:操作数量比较小的比较方便;可以直接操作,不用来回操作,也可以不用刷新。比如我们要删除某一条记录的时候,就可以直接使用这种方式了
关于Ajax
首先Ajax不是一门新语言,它是异步的JavaScript和xml,也就是一种异步请求更新技术,它是用JavaScript编写,与xml的关系就是可以读取和返回xml文件。
Ajax的核心对象就是xmlHttpRequest,xmlHttpRequest用于在后台与服务器交换数据,也就是说可以在不重新加载整个网页的情况下,对网页的某部分进行更新
方法:
①open(method,url,async)
method:请求的类型,主要是GET和POST
url:文件在服务器上的位置
async:true(异步)false(同步)
②send(string)
string:仅用于POST请求
属性:
①readyState:
0:请求未初始化
1:服务器连接已建立
2:请求已经接收
3:请求处理中
4:请求已完成,且响应已就绪
②State:
200:“ok”
404:未找到页面
③responseText:获取字符串形式的响应数据
④responseXML:获得XML形式的响应数据
⑤onreadystatechange:存储函数(或函数名),每当readyState属性改变,就会调用该函数
原理:ajax通过XmlHttpRequest对象执行操作,其中XmlHttpRequest对象是在浏览器中内置的一个对象,其运行原理就相当于创建了一个请求代理,通过代理去完成与服务器的交互,交互的过程用户不需要等待,还可以执行其它的操作,交互完成以后,代理再将交互的结果返回给用户页面
第一步:创建xmlHttpRequest对象
var xmlhttp; if (window.XMLHttpRequest){ // IE7+, Firefox, Chrome, Opera, Safari创建方式 xmlhttp = new XMLHttpRequest(); }else { // IE6, IE5 创建方式 xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); }
第二步:设置open()方法和setRequestHeader()方法参数,将请求方式,请求目的地和请求类型设置到open方法中,如果是post请求,则需要设置setRequestHeader()参数
第三步:发送执行,利用send方法,与服务器进行真正的交互执行
第四步:获得执行结果,首先判断执行是否完成,然后通过js操作dom,将返回的responseText返回到页面
xmlhttp.onreadystatechange= function () { //判断是否发送成功,是否找到请求页面 if (xmlhttp.readyState == 4 && xmlhttp.status == 200){ //操作页面元素 document.getElementById("myDiv").innerHTML = xmlhttp.responseText; } };
jQuery封装了Ajax技术,通过调用ajax()函数,就可以进行网络请求了。
回调函数
如果要处理$.ajax()得到的数据,则需要使用回调函数,beforeSend、error、dataFilter、success、complete。
beforeSend:在发送请求之前调用,并且传入一个XMLHttpReuqest作为参数
error:在请求出错时调用,传入XMLHttpRequest对象,描述错误类型的字符串以及一个异常对象
dataFilter:在请求成功之后调用,传入返回的数据以及“dataType”参数的值,并且必须返回新的数据(可能是处理过)传递给success回调函数
success:当请求之后调用,传入返回后的数据,以及包含成功代码的字符串
complete:当请求完成之后调用这个函数,无论成功或失败,传入XMLHttpRequest对象,以及一个包含成功或错误代码的字符串
数据类型 $.ajax()函数依赖服务器提供的信息来处理返回的数据。如果服务器报告说返回的数据是XML,那么返回的结果就可以用普通的XML方法或者jQuery的选择器来遍历。如果见得到其他类型,比如HTML,则数据就以文本形式来对待。 通过dataType选项还可以指定其他不同数据处理方式。除了单纯的XML,还可以指定 html、json、jsonp、script或者text。 其中,text和xml类型返回的数据不会经过处理。数据仅仅简单的将XMLHttpRequest的responseText或responseHTML属性传递给success回调函数, '''注意''',我们必须确保网页服务器报告的MIME类型与我们选择的dataType所匹配。比如说,XML的话,服务器端就必须声明 text/xml 或者 application/xml 来获得一致的结果。 如果指定为html类型,任何内嵌的JavaScript都会在HTML作为一个字符串返回之前执行。类似的,指定script类型的话,也会先执行服务器端生成JavaScript,然后再把脚本作为一个文本数据返回。 如果指定为json类型,则会把获取到的数据作为一个JavaScript对象来解析,并且把构建好的对象作为结果返回。为了实现这个目的,他首先尝试使用JSON.parse()。如果浏览器不支持,则使用一个函数来构建。JSON数据是一种能很方便通过JavaScript解析的结构化数据。如果获取的数据文件存放在远程服务器上(域名不同,也就是跨域获取数据),则需要使用jsonp类型。使用这种类型的话,会创建一个查询字符串参数 callback=? ,这个参数会加在请求的URL后面。服务器端应当在JSON数据前加上回调函数名,以便完成一个有效的JSONP请求。如果要指定回调函数的参数名来取代默认的callback,可以通过设置$.ajax()的jsonp参数。 注意,JSONP是JSON格式的扩展。他要求一些服务器端的代码来检测并处理查询字符串参数。更多信息可以参阅 最初的文章。 如果指定了script或者jsonp类型,那么当从服务器接收到数据时,实际上是用了<script>标签而不是XMLHttpRequest对象。这种情况下,$.ajax()不再返回一个XMLHttpRequest对象,并且也不会传递事件处理函数,比如beforeSend。 发送数据到服务器 默认情况下,Ajax请求使用GET方法。如果要使用POST方法,可以设定type参数值。这个选项也会影响data选项中的内容如何发送到服务器。 data选项既可以包含一个查询字符串,比如 key1=value1&key2=value2 ,也可以是一个映射,比如 {key1: 'value1', key2: 'value2'} 。如果使用了后者的形式,则数据再发送器会被转换成查询字符串。这个处理过程也可以通过设置processData选项为false来回避。如果我们希望发送一个XML对象给服务器时,这种处理可能并不合适。并且在这种情况下,我们也应当改变contentType选项的值,用其他合适的MIME类型来取代默认的 application/x-www-form-urlencoded 。 高级选项 global选项用于阻止响应注册的回调函数,比如.ajaxSend,或者ajaxError,以及类似的方法。这在有些时候很有用,比如发送的请求非常频繁且简短的时候,就可以在ajaxSend里禁用这个。更多关于这些方法的详细信息,请参阅下面的内容。 如果服务器需要HTTP认证,可以使用用户名和密码可以通过username和password选项来设置。 Ajax请求是限时的,所以错误警告被捕获并处理后,可以用来提升用户体验。请求超时这个参数通常就保留其默认值,要不就通过jQuery.ajaxSetup来全局设定,很少为特定的请求重新设置timeout选项。 默认情况下,请求总会被发出去,但浏览器有可能从他的缓存中调取数据。要禁止使用缓存的结果,可以设置cache参数为false。如果希望判断数据自从上次请求后没有更改过就报告出错的话,可以设置ifModified为true。 scriptCharset允许给<script>标签的请求设定一个特定的字符集,用于script或者jsonp类似的数据。当脚本和页面字符集不同时,这特别好用。 Ajax的第一个字母是asynchronous的开头字母,这意味着所有的操作都是并行的,完成的顺序没有前后关系。$.ajax()的async参数总是设置成true,这标志着在请求开始后,其他代码依然能够执行。强烈不建议把这个选项设置成false,这意味着所有的请求都不再是异步的了,这也会导致浏览器被锁死。 $.ajax函数返回他创建的XMLHttpRequest对象。通常jQuery只在内部处理并创建这个对象,但用户也可以通过xhr选项来传递一个自己创建的xhr对象。返回的对象通常已经被丢弃了,但依然提供一个底层接口来观察和操控请求。比如说,调用对象上的.abort()可以在请求完成前挂起请求。
如果提交的数据有数组,需要加traditional:true,比如 $.ajax({ url:"", type:"POST", data:{'k':[1,2,3]}, traditional:true, success:function(arg){ } }) 注:data里面的key-value中的value不支持字典 form表单提交时: var data = $("#fm").serialize() 获取要提交的所有数据
示例:
<!--通过对话框+ajax来提交数据--> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> * { margin: 0; padding: 0; background-color: white; } .outer1 { margin-left: 30px; margin-top: 30px; width: 100%; height: 1000px; } .shade { position: fixed; top: 0; left: 0; right: 0; bottom: 0; opacity: 0.5; background-color: grey; } .btn { background-color: red; color: white; width: 50px; height: 40px; font-size: 20px; } .hide { display: none; } .outer2 { position: absolute; background-color: white; width: 400px; height: 300px; top: 50%; left: 50%; margin-top: -150px; margin-left: -200px; } #inner{ margin-top: 100px; margin-left: 120px; } #errorMsg{ color: red; font-size: 10px; } </style> </head> <body> <div class="outer1"> <h1>首页</h1> <input class="btn" type="button" value="登陆" onclick="signIn()"> </div> <!--遮罩--> <div class="shade hide"></div> <div class="outer2 hide"> <form id="inner"> {% csrf_token %} <p><input type="text" name="username" placeholder="请输入用户名"></p> <p><input type="password" name="pwd" placeholder="请输入密码" ></p> <div> <label id="errorMsg"></label> <input type="button" id="confirm" value="登陆"/> <input type="button" id="cancel" value="取消"/> </div> </form> </div> <script src="/static/js/jquery-3.2.0.min.js"></script> <script> function signIn() { $(".outer2").removeClass("hide"); $(".shade").removeClass("hide"); } $(function () { cancelIn(); confirmIn(); }); function cancelIn() { $("#cancel").click(function () { $(".outer2").addClass("hide"); $(".shade").addClass("hide"); }); } function confirmIn() { $("#confirm").click(function () { //确认登陆 //通过ajax来提交 $.ajax({ url:"/ajax_sign_in/", type:"POST", dataType:"JSON", data:$("#inner").serialize(), success:function (data) { var state = data.status; console.log(data); if (state == 1){ $(".outer2").addClass("hide"); $(".shade").addClass("hide"); }else { $("#errorMsg").text(data.msg); } } }) }); } </script> </body> </html>
# views部分 def ajax_sign_in(request): # 获取ajax提交过来的数据 data = {"status":1,"msg":None} u = request.POST.get("username") p = request.POST.get("pwd") # 查询数据库,看用户名和密码是否对应的上 user = models.User.objects.filter(username=u).first() if user: # 如果用户存在,判断用户名是否存在 if user.pwd == p: return HttpResponse(json.dumps(data)) else: data["status"] = 0 data["msg"] = "密码不正确" return HttpResponse(json.dumps(data)) else: data["status"] = 0 data["msg"] = "用户不存在" return HttpResponse(json.dumps(data)) def home(request): return render(request,"home.html")
# urls部分 url(r'^home/', v2.home), url(r'^ajax_sign_in/', v2.ajax_sign_in),
效果图:
![]()
分页
<!-- pager页 --> {% if page.has_previous %} <a href="/inner_pager?p={{ page.previous_page_number }}">上一页</a> {% endif %} {% if page.has_next %} <a href="/inner_pager?p={{ page.next_page_number }}">下一页</a> {% endif %} <!--当前页和总页数--> <span>{{ page.number }}/{{ page.paginator.num_pages }}</span>
<!inner_pager页--> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>内置分页</h1> <ul> {% for p in page %} <li>{{ p }}</li> {% endfor %} </ul> {% include 'pager.html'%} </body> </html>
# views下内置分页逻辑处理 from django.core.paginator import Paginator,EmptyPage,PageNotAnInteger L = [] for i in range(999): L.append("测试数据%s" % i) def inner_pager(request): '''内置分页''' # per_page 每页显示条目数列 # count 数据总个数 # num_pagers 总页数 # page_range 总页数索引范围 # page page对象(封装了是否有上一页和下一页) paginator = Paginator(L,10) # 获取当前页 p = request.GET.get("p") if p: curent_page = int(p) else: curent_page = 1 try: # 获取page对象 page = paginator.page(curent_page) # has_next 是否有上一页 # next_page_number 下一页页码 # has_previous 是否有上一页 # previous_page_number 上一页页码 # object_list 分页之后的数据列表 # number当前页 # paginator paginator对象 except PageNotAnInteger: page = paginator.page(1) except EmptyPage: page = paginator.page(paginator.num_pages) return render(request,"inner_pager.html",{"page":page})
内置分页效果图
![]()
分页扩展
# 通过自定义Paginator对象来实现 class CustomPaginatior(Paginator): def __init__(self,current_page,per_pager_num,*args,**kwargs): ''' :param current_page: 当前页 :param per_pager_num: 最多显示的页面数量 :param agrs: :param kwagrs: ''' self.current_page = int(current_page) self.per_pager_num = int(per_pager_num) super(CustomPaginatior,self).__init__(*args,**kwargs) def page_num_range(self): # 定义当前页函数 # self.current_page 当前页 # self.per_pager_num 最多显示的页码数 # self.num_pages 总页数 # 总页数小于最大显示的页数 if self.num_pages < self.per_pager_num: return range(1,self.num_pages+1) # 总页数特别多,需要根据当前页来进行判断 part = int(self.per_pager_num / 2) if self.current_page <= part: return range(1,self.per_pager_num+1) # 极值判断 if (self.current_page + part) > self.num_pages: return range(self.num_pages-self.per_pager_num+1,self.num_pages + 1) return range(self.current_page - part,self.current_page+part+1)
pager页面进行修改:
{% if page.has_previous %} <a href="/inner_pager?p={{ page.previous_page_number }}">上一页</a> {% endif %} <!--分页扩展--> {% for i in page.paginator.page_num_range %} {% if i == page.number %} <a class="P" href="/inner_pager?p={{ i }}">{{ i }}</a> {% else %} <a href="/inner_pager?p={{ i }}">{{ i }}</a> {% endif %} {% endfor %} {% if page.has_next %} <a href="/inner_pager?p={{ page.next_page_number }}">下一页</a> {% endif %} <!--当前页和总页数--> <span>{{ page.number }}/{{ page.paginator.num_pages }}</span>
inner_pager函数里边,修改:
paginator = Paginator(L,10) 为 paginator = CustomPaginatior(curent_page,11,L,10),其它不变
效果图:
自定义分页
# 自定义分页 class Pagination: def __init__(self,totalCount,currentPage,perPageItemNum=10,maxPageNum=7): # 数据总个数 self.total_count = totalCount # 当前页 try: v = int(currentPage) # 如果当前页小于0,让当前页等于1 if v <= 0: v = 1 self.current_page = v except Exception as e: self.current_page = 1 # 每页显示条数 self.per_page_item_num = perPageItemNum # 最多显示的页数 self.max_page_num = maxPageNum def start(self): ''' 切片开始页 :return: ''' return (self.current_page-1)*self.per_page_item_num def end(self): ''' 切片结束页 :return: ''' return (self.current_page + 1) * self.per_page_item_num @property def num_pages(self): ''' 总页数 :return: ''' a,b = divmod(self.total_count,self.per_page_item_num) if b == 0: return a return a + 1 def page_num_range(self): ''' 显示页码的范围 :return: ''' # 总页数小于最多显示的页数 if self.num_pages < self.max_page_num: return range(1,self.num_pages + 1) # 总页数特别多的情况 part =int(self.max_page_num / 2) if self.current_page <= part: return range(1,self.max_page_num + 1) # 极值判断 if (self.current_page + part) > self.num_pages: return range(self.num_pages -self.max_page_num + 1,self.num_pages + 1) return range(self.current_page - part,self.current_page+part+1) def page_str(self): ''' 定义显示的页面界面 :return: ''' page_list = [] first = "<li><a href='/my_pager?p=1'>首页</a></li>" page_list.append(first) if self.current_page == 1: prev = "<li><a href='#'>上一页</a>" else: prev = "<li><a href='/my_pager?p=%s'>上一页</a></li>" % (self.current_page - 1,) page_list.append(prev) for i in self.page_num_range(): if i == self.current_page: temp = "<li ><a class='P' href='/my_pager?p=%s'>%s</a></li>" % (i, i) else: temp = "<li><a href='/my_pager?p=%s'>%s</a></li>" % (i, i) page_list.append(temp) if self.current_page == self.num_pages: nex = "<li><a href='#'>下一页</a>" else: nex = "<li><a href='/my_pager?p=%s'>下一页</a></li>" % (self.current_page + 1,) page_list.append(nex) last = "<li><a href='/my_pager?p=%s'>尾页</a></li>" % (self.num_pages,) page_list.append(last) return "".join(page_list)
# Pagination的使用
from app02 import pager def my_pager(request): ''' 自定义分页 :param request: :return: ''' # 获取当前页 p = request.GET.get("p") if p: curent_page = int(p) else: curent_page = 1 page_obj = pager.Pagination(999,curent_page) data_list = L[page_obj.start():page_obj.end()] return render(request,"my_pager.html",{"data":data_list,"page_obj":page_obj})


浙公网安备 33010602011771号