Xadmin控件的实现:〇四查询视图二——分页效果的实现

在前面的一章里我们实现了如何在一个页面里按照表格的方式显示出来所需要的数据,但是随着数据量的增加,需要做一个分页的效果。

添加模拟数据

 为了能更好的实现分页的效果,我们用下面的代码生成500条新的数据

def test(request):
    for i in range(0,500):
        pub = models.Publisher.objects.get(id = (i%2+1))
        book = models.Books(title = str(i),price = i,publisher=pub)
        book.save()
    return HttpResponse('OK')

创建数据以后,我们在访问Books这个表

 

是个超级长的页面,明显不符合我们平时的使用需求。这时候就需要我们这一章讲的分页了

基础版本分页功能

以前写了个博客,就讲了如何实现分页,可以点击查看

基础版的分页代码

我们可以把前面的那个分页的代码直接贴过来,导入以后看看怎么修改

修改后的分页代码如下

from django.utils.safestring import mark_safe
class Page_Cut():
    def __init__(self,page,url_prefix,data_totle,data_per_page=10,page_show_num=11):
        """
        :param: page:当前页码
        :url_prefix:url前缀
        :data_totle:总数据量
        :date_per_page:每页显示数据条数,默认值为10
        :page_show_num:显示的分页数量,默认值为11
        """
        self.url_prefix = url_prefix  #url前缀
        page_totle,m = divmod(data_totle,data_per_page)
        page_totle = page_totle if not m else page_totle +1    #计算总页码数
        self.page_totle = page_totle

        self.page_show_num = page_show_num if page_show_num < self.page_totle else self.page_totle  #显示最大页码数

        self.data_per_page = data_per_page

        page = 1 if page<1 else page
        page = page_totle if page>page_totle else page

        self.page = page

        

        if page_totle < page_show_num:
            page_show_num = page_totle

        page_half = page_show_num // 2                #中间页码数

        page_start = page - page_half
        page_end = page + page_half 

        if page_start <= 1:
            page_start = 1
            page_end = page_show_num


        if page_end >= page_totle:
            page_end = page_totle
            page_start = page_totle - page_show_num +1

        self.page_start = page_start
        self.page_end = page_end

    @property               #静态属性,调用的时候可以省略括号
    def ID_start(self):     #当前页开始数据ID
        return (self.page-1) * self.data_per_page
        
        

    @property
    def ID_end(self):
        return(10 * self.page)



    def page_html(self):
        html_begin = '<nav aria-label="Page navigation"> <ul class="pagination">'

        last_page = self.page-1 if self.page > 1 else 1

        if last_page == 1:
            html_last = """
            <li> 
            <a href="{0}?page={1}">
            <span aria-hidden="true">&laquo;</span>
            </a>
            </li>""".format(self.url_prefix,last_page)
        
        else:
            html_last = """
            <li>
            <a href="{0}?page={1}" aria-label="Previous">
            <span aria-hidden="true">&laquo;</span>
            </a>
            </li>""".format(self.url_prefix,last_page)


        page_cut_html = "<li><a href='{}?page=1'>首页</a></li>".format(self.url_prefix)  #html开始为跳转首页标签
        
        for i in range(self.page_start,self.page_end+1):
            page_cut_html += """
            <li><a href='{0}?page={1}'>{1}</a></li>""".format(self.url_prefix,i)

        page_cut_html += "<li><a href='{0}?page={1}'>尾页</a></li>".format(self.url_prefix,self.page_totle)

        html_end = """
        <li>
        <a href="{0}?page={1}" aria-label="Next">
        <span aria-hidden="true">&raquo;</span>
        </a>
        </li></ul></nav>""".format(self.url_prefix,self.page_end)


        page_html = html_begin + html_last + page_cut_html + html_end
        
        return mark_safe(page_html)
/My_util/PageCut.py

和前面的一章里的分页的代码不同的地方就是修改了一下路径拼接的地方,url_prefix直接传过来的就是当前展示的路径,然后加上参数?page就行了。

然后对应的list视图里要大概修改一下,思路是添加下面的代码

1 page = int(request.GET.get('page',1))
2 
3 data_totle = all_data.count()
4 page_cut = Page_Cut(page=page,url_prefix=self.get_list_url() ,data_totle=data_totle)
5 cut_html = page_cut.page_html
6 
7 cut_data = all_data[page_cut.ID_start:page_cut.ID_end]

也就是生成一段html代码,添加到模板中。

然后就搞定了!

 

 主要看地址栏里的URL。

 带有参数的分页效果

 在页面里可以看一下分页按钮的pref属性,我们是写成固定的了,只包含了page这个必须的参数。

参考一下博客园里的检索时候对结论的分页

 

 注意一下URL,这里的URL里是带有filter结论的(filter的检索功能我们以后会讲到,这里主要讲分页的时候怎么添加pag以外的参数)

其实思路就是我们在视图中把request.GET作为参数发送给Page_Cut。因为request.GET中包含了是以QuerySet的方式包含了参数。

比方我们想查询id大于2,价格小于100的第二页,url的样式大概是这样的

http://127.0.0.1:8000/Xadmin/CRUD/books/?page=2&id_gt=2&price_lt=100

然后我们打印一下request.GET

<QueryDict: {'page': ['2'], 'id_gt': ['2'], 'price_lt': ['100']}>

可以看出来这个样式

QuerySet对象有一个方法可以把整个字典拼成URL的形式

print('GET:',request.GET)
print('GET.encode:',request.GET.urlencode())

##########输出#########
GET: <QueryDict: {'page': ['2'], 'id_gt': ['2'], 'price_lt': ['100']}>
GET.encode: page=2&id_gt=2&price_lt=100

所以就可以用这个方法来在page_cut里生成html标签的时候追加所有的参数,其实这样更简单,只需要在生成html的a标签的时候吧GET里的page值一改就行了。

下面就是修改后的带有参数传递的分页代码

from django.utils.safestring import mark_safe
from copy import deepcopy


class Page_Cut():
    def __init__(self,page,url_prefix,data_totle,param,data_per_page=10,page_show_num=11):
        """
        :param: page:当前页码
        :url_prefix:url前缀
        :data_totle:总数据量
        :date_per_page:每页显示数据条数,默认值为10
        :page_show_num:显示的分页数量,默认值为11
        """
        self.param = deepcopy(param)
        
        self.url_prefix = url_prefix  #url前缀
        page_totle,m = divmod(data_totle,data_per_page)
        page_totle = page_totle if not m else page_totle +1    #计算总页码数
        self.page_totle = page_totle

        self.page_show_num = page_show_num if page_show_num < self.page_totle else self.page_totle  #显示最大页码数

        self.data_per_page = data_per_page

        page = 1 if page<1 else page
        page = page_totle if page>page_totle else page

        self.page = page

        

        if page_totle < page_show_num:
            page_show_num = page_totle

        page_half = page_show_num // 2                #中间页码数

        page_start = page - page_half
        page_end = page + page_half 

        if page_start <= 1:
            page_start = 1
            page_end = page_show_num


        if page_end >= page_totle:
            page_end = page_totle
            page_start = page_totle - page_show_num +1

        self.page_start = page_start
        self.page_end = page_end

    @property               #静态属性,调用的时候可以省略括号
    def ID_start(self):     #当前页开始数据ID
        return (self.page-1) * self.data_per_page
        
        

    @property
    def ID_end(self):
        return(10 * self.page)



    def page_html(self):
        print(self.param)
        html_begin = '<nav aria-label="Page navigation"> <ul class="pagination">'

        last_page = self.page-1 if self.page > 1 else 1

        if last_page == 1:
            self.param['page'] = last_page
            html_last = """
            <li> 
            <a href="{0}?{1}">
            <span aria-hidden="true">&laquo;</span>
            </a>
            </li>""".format(self.url_prefix,self.param.urlencode())
        
        else:
            html_last = """
            <li>
            <a href="{0}?{1}" aria-label="Previous">
            <span aria-hidden="true">&laquo;</span>
            </a>
            </li>""".format(self.url_prefix,self.param.urlencode())

        self.param['page'] = 1
        page_cut_html = "<li><a href='{}?{}'>首页</a></li>".format(self.url_prefix,self.param.urlencode())  #html开始为跳转首页标签
        
        for i in range(self.page_start,self.page_end+1):
            self.param['page'] = i
            page_cut_html += """
            <li><a href='{0}?{1}'>{2}</a></li>""".format(self.url_prefix,self.param.urlencode(),i)

        self.param['page'] = self.page_totle
        page_cut_html += "<li><a href='{0}?{1}'>尾页</a></li>".format(self.url_prefix,self.param.urlencode())


        self.param['page'] = self.page_end
        html_end = """
        <li>
        <a href="{0}?{1}" aria-label="Next">
        <span aria-hidden="true">&raquo;</span>
        </a>
        </li></ul></nav>""".format(self.url_prefix,self.param.urlencode())


        page_html = html_begin + html_last + page_cut_html + html_end
        
        return mark_safe(page_html)
My_util/PageCut.py

要注意的是我们在传参数的时候用了深拷贝。具体原因也就不用解释了,Django里的源代码里应该是对request.GET做了保护,正常情况下防止变量被污染是不能更改的,所以我们需要用deepcopy重新复制一份。

或者用.copy()的方法浅拷贝复制一份。

初步的分页功能就完成了。 

posted @ 2020-08-16 11:15  银色的音色  阅读(500)  评论(0编辑  收藏  举报