Django分页、Ajax

一、Django的分页:

分页是为了减少一次性从数据库读过多的数据。

先说一下offset和limit。

语句1:select * from student limit 9,4
语句2:slect * from student limit 4 offset 9

这两条语句的查询结果是一样的。同样可以完成分页的功能。

1、Django内置分页: 

from django.core.paginator import EmptyPage,PageNotAnInteger,Paginator

def index(request):
    current_page = request.GET.get("current_page")
    if current_page == None:
        current_page = 1
    paginator = Paginator(slist, 10)  # slist是数据,10代表每一页的显示多少条
    # 这个page对象包含了,是否具有上一页,是否有下一页
    page = paginator.page(current_page)  # 在这里做异常判断,如果用户输入不合法就报异常
    return render(request, "index.html", {"slist": page, "current_page": current_page})

前端页面:

# 循环打印数据
    {% for row in slist.object_list %} # 已经分好页的数据
  • {{ row.name }}
  • {% endfor %}
# 判断是否有上一页 {% if slist.has_previous %} # 上一页的页码 上一页 {% endif %} 总页数{{ slist.paginator.num_pages }}, 当前页:{{ slist.number }} # 判断是否有下一页 {% if slist.has_next %} # 下一页的页码 下一页 {% endif %}

两个重要的对象: Paginator 和 page对象。

Paginator:

per_page: 每页显示记录数量

count:    数据总个数

num_pages: 总页数

page_range:  总页数的索引范围,如: (1,10),(1,200)

page:     page对象  page(2)  代表第二页数据的对象

 page:

has_next              是否有下一页

next_page_number      下一页页码

has_previous          是否有上一页

previous_page_number  上一页页码

object_list           分页之后的当前页数据列表

number                当前页

paginator             paginator对象,父类对象

※:可以建一个模板,每次分页都include,提高代码的可重用性。至此Django的内置分页已做好,并没有什么样式,下面开始自定制。

2、扩展Dajngo的内置分页:

通过继承Paginator的方式进行自定义类的方式进行分页。

def index(request):
    current_page = request.GET.get("current_page")
    if current_page == None:
        current_page = 1
    #  参数:当前页、页码最大显示、数据列表、每页多少数据
    paginator = CustomPaginator(current_page, 5, slist, 10)
    page = paginator.page(current_page)  # 在这里应该做异常判断,如果用户输入不合法就报异常
    return render(request, "index.html", {"slist": page, "current_page": current_page})

class CustomPaginator(Paginator):

    # 初始化调用父类的方法
    def __init__(self, current_page, per_num, *args, **kwargs):
        self.current_page = int(current_page)
        self.per_page = per_num
        super().__init__(*args, **kwargs)

    # 自己定义一个方法进行页码的显示
    def getNum(self):
        self.part = self.per_page//2
        #  当前页码数小于总页数
        if self.num_pages < self.per_page:
            return range(1,self.num_pages+1)
        # 当前页小于显示页码的一半时
        if self.current_page <= self.part:
            return range(1, self.per_page+1)
        # 当当前页加上显示的页码一半大于总页数时
        if (self.current_page+self.part) > self.num_pages:
            return range(self.num_pages-self.per_page+1,self.num_pages+1)
        # 当前页大于显示页码的一半时
        if self.current_page > self.part:
            return range(self.current_page-self.part, self.current_page+self.part+1)

前端页面:

# 进行数据的遍历
    {% for row in slist.object_list %}
  • {{ row.name }}
  • {% endfor %}
# 进行页码遍历 {% if slist.has_previous %} 上一页 {% endif %} {% for item in slist.paginator.getNum %} {% if item == slist.number %} {{ item }} {% else %} {{ item}} {% endif %} {% endfor %} {% if slist.has_next %} 下一页 {% endif %}

3、自定义分页:

通过自己写分页的类。

class Paginator(object):

    # 参数: 每页的记录数、当前页码、显示最大页码数、总数据条数
    def __init__(self, per_count_page, current_page, per_index_page, total_count):
        self.per_count_page = per_count_page
        self.current_page = int(current_page)
        self.per_index_page = per_index_page
        self.total_count = total_count
        self.mid = self.per_index_page//2
    
    # 开始页数
    def start(self):
        return (self.current_page - 1) * self.per_count_page
    
    # 结束页数
    def end(self):
        return self.current_page * self.per_count_page
    
    # 计算总页数
    @property
    def page_num(self):
        self.a, b = divmod(self.total_count, self.per_count_page)
        if b != 0:
            return self.a+1   # 在这里最好直接返回一个值,而不是当前的形式
        else:
            return self.a

    
    # 计算页码显示样式
    def getNum(self):  #         self.part = self.per_page//2
        #  当前页码数小于总页数
        if self.page_num < self.per_index_page:
            return range(1, self.page_num+1)
        if self.current_page <= self.mid:
            return range(1, self.per_index_page+1)
        if (self.current_page+self.mid) > self.page_num:
            return range(self.page_num-self.per_index_page+1,self.page_num+1)
        if self.current_page > self.mid:
            return range(self.current_page-self.mid, self.current_page+self.mid+1)

    # 将每个a标签放入,列表中,前端页面不用再循环显示
    def page_indexs(self):
        index_list = []
        first = '首页'
        index_list.append(first)
        if self.current_page-1:
            top = '上一页'
            index_list.append(top)
        for i in self.getNum():
            # 寻找当前页
            if self.current_page == i:
                temp = ''+str(i)+''
            else:
                temp = ''+str(i)+''
            index_list.append(temp)
        if self.current_page != (self.a+1):
            bottom = '下一页'
            index_list.append(bottom)
        last = '尾页'
        index_list.append(last)
        return "".join(index_list)  # 转换成字符串

前端页面:


# 进行数据遍历
    {% for row in data %}
  • {{ row.name}}
  • {% endfor %}
# 后台遍历好了,直接显示 {{ pages|safe }}

更多内容详见:https://docs.djangoproject.com/en/2.2/topics/pagination/

二、Ajax部分

1、概述:Ajax 的全称是Asynchronous JavaScript and XML(异步 JavaScript 和 XML),是指一种创建交互式网页应用的网页开发技术。是一种用于创建快速动态网页的技术,是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。

2、基本原理

Django分页、Ajax_第1张图片

3、$.ajax的一般格式

$.ajax({
 url:“路径”,
 data:{key1:value1},   // value1可以是数组类型,但不能是字典类型,如果非要传字典类型就把字典传成字符串
 type:'POST/GET',    //数据的提交方式:get和post
  dataType:’json’,    //  数据的返回值类型,当返回的数据类型和dataType定义不一样时,不会触发success函数。
   traditional:True,
 success:function(str){	//成功回调函数,str就是后台传送回来的信息。在回调函数中无法用$(this) 会无法定位到准确位置
  },
 error:function (err){	//失败回调函数
       
 }
});

dataType 的一些参数值:

当dataType:"json"时,会自动解析json字符串。

当dataType:"text"时,不会进行任何处理。默认就是text。

当dataType:"xml"时,会自动转化为xml。

dataType也可以是html

一些其他的属性:

var data = $("表单的id").serialize() // serialize()方法会自动提交表单的属性到data下。

后台接收到的数据:


Ajax传数组数据时:data:{slist:[1,2,3,4,5]}     后台收到的是   ,这样是不符合常理的。
当设置traditional:true。后台接收到的数据

比较Ajax和跳转新页面:

新url的方式进行修改:  好处是 独立的页面,数据量大、或者条目多的时候适合用。当用户输入错误时应该保留用户输入的正确字段。
Ajax方式进行修改:数据量小、或者条目少的时候适合用。是否刷新?一般刷新,除非性能要求。要考虑当前页码和自定义属性。

原生的Ajax:

为了解决手机app调用Ajax的问题,所以用原生的Ajax。

GET请求:

var xhr = new XMLhttprequest()   // 创建一个对象

xhr.open("GET","")   // open方法的两个参数 请求的方式,路径

xhr.onreadystatechange = function(){   // 回调函数
    if(xhr.readyState==4){    // 当readyState返回值为4时表示成功    
        console.log("接收成功")
    }
}  

xhr.send(null)  //  发送数据 

POST请求:

var xhr = new XMLhttprequest()   // 创建一个对象

xhr.open("POST","")   // open方法的两个参数 请求的方式,路径

xhr.onreadystatechange = function(){   // 回调函数
    if(xhr.readyState==4){    // 当readyState返回值为4时表示成功    
        console.log("接收成功")
    }
}  
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset-UTF-8")   // 需要设置请求头否则django不认识
xhr.send("name=default")  //  发送数据 

伪Ajax请求:

通过iframe的无刷新返回数据的特性,并且能很好的解决兼容性的问题,所以有时候通过伪Ajax请求的方式。

首先在form标签加上target属性,target的值是iframe的name属性的值。

还需要为iframe标签绑定onload属性,不过不直接写在标签上,而是当点击提交以后通过 js 进行绑定。onload属性相当于回调函数。

document.getElementById("iframe").onload = reloading;

处理iframe的返回值:拿到后台返回的值

原生的js方式:
    document.getElementById("iframe").contentWindow.document.body.innerHTML

jQuery的方式:
    $("#iframe").contents().find("body").html()    

Ajax文件上传:

我们可以为上传按钮进行onchange函数的定义;

  //  当选中文件以后自动上传

原生Ajax:

var data = new Formdata();   //  通过Formdata的方式进行上传 
data.append("img", document.getElementById("load").files[0])  // 获取文件标签的内容
var xhr = new XMLHttpRequest();
xhr.open("post","/upload");
xhr.onreadystatechange() = function(){
    if(xhr.readystate == 4){
        console.log(xhr.responseText)
    }
}
xhr.send(data);   //  在这里直接进行发送

jQuery:

var data = new Formdata();
data.append("img", $("#load")[0].files[0])
$.ajax({
    url:"/upload",
    type:"POST",
    data:data,
    success:function(arg){
        console.log(arg)
    }
    processData: false,    // 告诉jQuery不要去处理发送的数据, 发送对象。
    contentType: false,     // 告诉jQuery不要去设置Content-Type请求头
})

iframe的形式上传文件: 

HTML:



    
预览
------------------------------------------------------------------------- js: function upload() { document.getElementById("if").onload = show; document.getElementById("form_data").submit() } function show() { var x=this.contentWindow.document.body.innerHTM; document.getElementById("up").innerHTML = "" }

跨域Ajax请求:

由于浏览器有同源策略的限制,所以无法正常接收其他服务器的响应信息。所以通过src属性进行跨域访问。我们通过jsonp的方式进行苦于的访问。以jsonp的形式进行跨域访问,只能以GET的方式进行。

原生js:

js部分

function show1(){

        var img = document.createElement("script");  // 创建一个script标签
        img.src = " http://127.0.0.1:8080/outer";    // 设置请求路径
        document.head.appendChild(img);     //  在头内添加信息
        document.head.removeChild(img); // 拿到数据就删除
     }

function fuck(msg) {
        console.log(msg)
    }

-------------------------------------------------------------------
views

def outer(request):
    return HttpResponse("fuck('外界的响应')")   // 返回一个函数名包裹信息,实际上返回的是函数

jQuery:

js部分

function show1(){
        $.ajax({
            url:" http://127.0.0.1:8080/outer",
            type:"get",
            success:function (msg) {
                console.log(msg)
            },
            dataType:"jsonp",    //  当类型是jsonp的形式时,会自动生成标签等
            jsonp:"callback",    //  设置参数名
            jsonpcallback:"fuck",   // 设置回调函数

        })
    }

    function fuck(msg) {
        console.log(msg)
    }

-------------------------------------------------------------------
views

def outer(request):
    name = request.GET.get("callback")    // 获取参数值
    return HttpResponse(name+"('外界的响应')")   // 返回一个函数名包裹信息

跨站资源共享(core):

通过设置头信息,让浏览器不再限制信息的返回,core的方式既可以GET请求也可以用POST请求

function show1(){
        $.ajax({
        url:"http://127.0.0.1:8080/outer/",
        type:"get",
        success:function (msg) {
            $("#content").text(msg);
        }
    })
}

-----------------------------------------------

views视图函数:

 

你可能感兴趣的:(Django,Python)