Django分页、Ajax

本文详细介绍了Django框架中的分页实现方法,包括内置分页、自定义分页及扩展分页功能,同时深入讲解了Ajax技术原理及其在网页开发中的应用,覆盖了$.ajax的使用、原生Ajax、文件上传、跨域请求等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、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})

前端页面:

# 循环打印数据
<ul>
    {% for row in slist.object_list %}  # 已经分好页的数据
        <li>{{ row.name }}</li>
    {% endfor %}
</ul>

# 判断是否有上一页
{% if slist.has_previous %}
    # 上一页的页码
    <a href="/index?current_page={{ slist.previous_page_number }}">上一页</a>
{% endif %}
总页数{{ slist.paginator.num_pages }}, 当前页:{{ slist.number }}

# 判断是否有下一页
{% if slist.has_next %}
    # 下一页的页码
    <a href="/index?current_page={{ slist.next_page_number }}">下一页</a>
{% 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)

前端页面:

# 进行数据的遍历
<ul>
    {% for row in slist.object_list %}
        <li>{{ row.name }}</li>
    {% endfor %}
</ul>

# 进行页码遍历
{% if slist.has_previous %}
    <a href="/index?current_page={{ slist.previous_page_number }}">上一页</a>
{% endif %}
{% for item in slist.paginator.getNum %}
    {% if item == slist.number %}
        <a href="/index?current_page={{ item }}" style="font-size: 40px">{{ item }}</a>
    {% else %}
       <a href="/index?current_page={{ item }}">{{ item}}</a>
    {% endif %}
{% endfor %}
{% if slist.has_next %}
    <a href="/index?current_page={{ slist.next_page_number }}">下一页</a>
{% endif %}

</body>

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 = '<a href="/index1?current_page=1">首页</a>'
        index_list.append(first)
        if self.current_page-1:
            top = '<a href="/index1?current_page=' + str(self.current_page - 1) + '">上一页</a>'
            index_list.append(top)
        for i in self.getNum():
            # 寻找当前页
            if self.current_page == i:
                temp = '<a style="font-size: 30px" href="/index1?current_page='+str(i)+'">'+str(i)+'</a>'
            else:
                temp = '<a href="/index1?current_page='+str(i)+'">'+str(i)+'</a>'
            index_list.append(temp)
        if self.current_page != (self.a+1):
            bottom = '<a href="/index1?current_page=' + str(self.current_page + 1) + '">下一页</a>'
            index_list.append(bottom)
        last = '<a href="/index1?current_page=' + str(self.a+1) + '">尾页</a>'
        index_list.append(last)
        return "".join(index_list)  # 转换成字符串

前端页面:

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

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

二、Ajax部分

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

2、基本原理

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下。

后台接收到的数据:
<QueryDict: {'slist': ['name=%E6%94%BE%E5%88%B0&pass=123&chose=third']}>

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

比较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属性的值。

<form method="post" action="" enctype="multipart/form-data" target="iframe">

还需要为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函数的定义;

<input type="file" onchange="change()">  //  当选中文件以后自动上传

原生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:

<iframe style="display: none" id="if" name="frame"></iframe>
<form id="form_data" method="post" action="/files/" enctype="multipart/form-data" target="frame">
    <div id="up"><span>预览</span></div>
    <input type="file" name="img" onchange="upload()">
    <input type="text">
</form>

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

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 = "<img src="+new_x.path+">"
    }

跨域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视图函数:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值