自定义分页的实现

放在项目的utils包中

自定义分页属于自己写的功能,把它放在项目的utils包中,py文件取名为page.py。

主要看类实现的方法——函数low鸡版不看了

page.py文件中的内容:总得来说就是后台拼接好标签~然后拿到前端显示出来——为每一个标签都加上一个方法就好~~

## 需要特别注意:因为这个CRM项目搜索与信息展示用了同一个视图函数~因此在分页中做了“保存搜索条件”的处理——保存搜索条件:就是搜索完成后,第一页显示的是搜索的结果,但是点击第二页如果不做处理的话第二页会显示“所有结果的第二页”,因此需要在分页这里做一下处理!

#自定义分页
#官方推荐,页码数为奇数
class PageNation:
    def __init__(self,base_url,current_page_num,total_counts,request,per_page_counts=10,page_number=5,):
        '''
        :param base_url:   分页展示信息的基础路径
        :param current_page_num:  当前页页码
        :param total_counts:  总的数据量
        :param per_page_counts:  每页展示的数据量
        :param page_number:  显示页码数
        '''
        self.base_url = base_url
        self.current_page_num = current_page_num
        self.total_counts = total_counts
        self.per_page_counts = per_page_counts
        self.page_number = page_number
        self.request = request
        try:
            self.current_page_num = int(self.current_page_num)

        except Exception:
            self.current_page_num = 1

        half_page_range = self.page_number // 2
        # 计算总页数~~divmod方法返回商跟余数!
        self.page_number_count, a = divmod(self.total_counts, self.per_page_counts)
        if self.current_page_num < 1:
            self.current_page_num = 1
        #有余数的话,说明还有一页有遗留的数据,需要给总的页数加1
        if a:
            self.page_number_count += 1

        ######################################################## 当前页码为0的话~会有问题,下面这样的标记有做处理!
        if self.current_page_num > self.page_number_count:
            self.current_page_num = self.page_number_count

        if self.page_number_count <= self.page_number:
            self.page_start = 1
            self.page_end = self.page_number_count
        else:
            # 当前页小于定制的页数的一半的话~就是前面的几页,前面只显示到第一条数据就好了!
            if self.current_page_num <= half_page_range:
                self.page_start = 1
                self.page_end = page_number
            # 当前页大于定制的页数的一半的话~就是后面的几页,后面顶头了,最后只显示最后一条的数据就好了!
            elif self.current_page_num + half_page_range >= self.page_number_count:
                # 起始页码等于~总页数减去显示的页码数+1~~不加1的话会多添加一个标签!
                self.page_start = self.page_number_count - self.page_number + 1
                self.page_end = self.page_number_count
            else:
                self.page_start = self.current_page_num - half_page_range
                self.page_end = self.current_page_num + half_page_range

        ## 下面的逻辑是:搜索时保存搜索条件的逻辑!!!
        ## 后面的 循环生成html标签 会用到urlencode()方法!注意后面格式化标签字符串的方法!
        import copy
        # request.GET['page'] = 2 #This QueryDict instance is immutable
        from django.http.request import QueryDict
        # print(type(request))
        # print(request)
        # print(request.GET)
        # request.GET方法返回的是一个QueryDict类型的数据,
        # 它有一个urlencode()方法,可以将它里面的键值对转换成 ?condition=qq&wd=1&page=3的格式!
        # 这样的格式发送GET请求后浏览器能认识

        # 深拷贝后可以改了,避免浏览器请求的地址堆叠
        # 因为深拷贝调用了__deepcopy__方法,看QueryDict的源码可知这个方法把不可变的那个属性又改成了True使之可变
        # (一开始_mutable为True,init方法mutable设置成False......这个过程得知道!)
        self.params = copy.deepcopy(self.request.GET)
        # params['page'] = current_page_num
        # query_str = params.urlencode()


    #数据切片依据,起始位置
    @property
    def start_num(self):
        ################################################ 这里有个问题:如果没有数据的话,必须给 self.current_page_num = 1~~
        ################################################
        if self.current_page_num == 0:
            self.current_page_num = 1
        start_num = (self.current_page_num - 1) * self.per_page_counts
        return start_num

    #数据切片依据,终止位置
    @property
    def end_num(self):
        end_num = self.current_page_num * self.per_page_counts
        return end_num

    # 拼接HTMl标签
    def page_html(self):
        tab_html = ''
        tab_html += '<nav aria-label="Page navigation" class="pull-right"><ul class="pagination">'
        # 首页
        self.params['page'] = 1
        showye = '<li><a href="{0}?{1}" aria-label="Previous" ><span aria-hidden="true">首页</span></a></li>'.format(
            self.base_url, self.params.urlencode())
        tab_html += showye
        # 上一页
        if self.current_page_num == 1:
            previous_page = '<li disabled><a href="#" aria-label="Previous" ><span aria-hidden="true">&laquo;</span></a></li>'
        else:
            previous_page = '<li><a href="{0}?page={1}" aria-label="Previous" ><span aria-hidden="true">&laquo;</span></a></li>'.format(
                self.base_url, self.current_page_num - 1)
        tab_html += previous_page

        ## 循环生成页码标签!
        for i in range(self.page_start, self.page_end + 1):
            self.params['page'] = i

            if self.current_page_num == i:

                one_tag = '<li class="active"><a href="{0}?{2}">{1}</a></li>'.format(self.base_url, i,self.params.urlencode()) #?condition=qq&wd=1&page=3
            else:
                one_tag = '<li><a href="{0}?{2}">{1}</a></li>'.format(self.base_url, i,self.params.urlencode())
            tab_html += one_tag

        # 下一页
        if self.current_page_num == self.page_number_count:
            next_page = '<li disabled><a href="#" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>'
        else:
            next_page = '<li><a href="{0}?page={1}" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>'.format(self.base_url, self.current_page_num + 1)
        tab_html += next_page
        # 尾页
        self.params['page'] = self.page_number_count
        weiye = '<li><a href="{0}?{1}" aria-label="Previous" ><span aria-hidden="true">尾页</span></a></li>'.format(
            self.base_url, self.params.urlencode())
        tab_html += weiye

        tab_html += '</ul></nav>'

        return tab_html


#函数low鸡版
def pagenation(base_url,current_page_num,total_counts,per_page_counts=10,page_number=5):
    '''
    total_counts数据总数
    per_page_counts每页分多少条数据
    page_number = 页码显示多少个
    current_page_num 当前页
    :return:
    '''
    # all_objs_list = models.Customer.objects.all()
    # total_counts = all_objs_list.count()
    # page_number = 5

    try:
        current_page_num = int(current_page_num)

    except Exception:
        current_page_num = 1


    half_page_range = page_number//2
    #计算总页数
    page_number_count,a = divmod(total_counts,per_page_counts)
    if current_page_num < 1:
        current_page_num = 1

    if a:
        page_number_count += 1
    if current_page_num > page_number_count:
        current_page_num = page_number_count

    start_num = (current_page_num - 1) * 10
    end_num = current_page_num * 10

    if page_number_count <= page_number:
        page_start = 1
        page_end = page_number_count
    else:
        if current_page_num <= half_page_range:
            page_start = 1
            page_end = page_number
        elif current_page_num + half_page_range  >= page_number_count:
            page_start = page_number_count - page_number + 1
            page_end = page_number_count
        else:
            page_start = current_page_num - half_page_range
            page_end = current_page_num + half_page_range

    #拼接HTMl标签
    tab_html = ''
    tab_html += '<nav aria-label="Page navigation"><ul class="pagination">'

    #上一页
    if current_page_num == 1:
        previous_page = '<li disabled><a href="#" aria-label="Previous" ><span aria-hidden="true">&laquo;</span></a></li>'
    else:
        previous_page = '<li><a href="{0}?page={1}" aria-label="Previous" ><span aria-hidden="true">&laquo;</span></a></li>'.format(base_url,current_page_num-1)
    tab_html += previous_page

    for i in range(page_start,page_end+1):
        if current_page_num == i:

            one_tag = '<li class="active"><a href="{0}?page={1}">{1}</a></li>'.format(base_url,i)
        else:
            one_tag = '<li><a href="{0}?page={1}">{1}</a></li>'.format(base_url, i)
        tab_html += one_tag


    #下一页
    if current_page_num == page_number_count:
        next_page = '<li disabled><a href="#" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>'
    else:
        next_page = '<li><a href="{0}?page={1}" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>'.format(base_url,current_page_num+1)
    tab_html+=next_page
    tab_html += '</ul></nav>'

    return tab_html,start_num,end_num

视图函数中的调用

视图函数中拿到对应的数据,然后根据上面的类实例化一下就好了~~

但是因为上面提到了“保存搜索条件”~~这里给出完整的get方法的视图函数:

#公户信息与私户信息用同一个视图函数实现!
class CustomerView(View):
    # 判断是公户还是私户的
    flag = None
    # get方法实现了展示所有公户与搜索功能
    # 搜索实现了保存搜索条件的分页逻辑--视图函数与page.py中~
    def get(self,request):
        condition = request.GET.get('condition',default='')
        wd = request.GET.get('wd',default='')
        # print(condition,wd)
        # 模糊匹配的,因此这里将条件字段拼接成模糊匹配的形式
        condition = condition+'__contains'

        # get:condition=qq&wd=1&page=2
        # <QueryDict: {'condition': ['qq'], 'wd': ['1'], 'page': ['2']}> #condition=qq&wd=1&page=2

        # wd有值 说明进行了搜索操作!
        if wd:
            # 实例化一个Q查询类的对象
            q = Q()
            # 指定多条件连接符号,默认是and的关系,如果是一个查询条件的话就不写了
            q.connector = 'or'
            # 往q中添加条件~可以添加多个,默认是and的关系
            # 注意~以元组的形式添加进去!
            q.children.append((condition, wd))  # 弄成这种形式:condition=qq&wd=1&page=2
            # q.children.append(('qq_name__contains', '小')) # 还可以额外加一些国定的条件
            # all_customers = models.Customer.objects.filter(name__contains=wd)
            # 这样可以用q来筛选了~
            # 如果是公户的话,全部筛选
            if request.path == reverse('customer:customers'):
                all_customers = models.Customer.objects.filter(q)
            # 私户的话 得选择当前销售的私户了
            else:
                q.connector = 'and'
                q.children.append((condition, wd))
                q.children.append(('consultant', request.user))
                all_customers = models.Customer.objects.filter(q)
        # else表示没有查询,返回所有的公户或私户的数据
        else:
            # 查询客户表中销售字段为空的~~就是公户或者私户的所有的数据
            # 根据路径判断访问的是公户的还是私户的
            if request.path == reverse('customer:customers'):
                # 表示公户
                self.flag = 0
                # 公户 表示没有销售
                all_customers = models.Customer.objects.filter(consultant__isnull=True)
            else:
                # 表示是私户
                self.flag = 1
                # 这时所有的信息应当是当前登陆用户的客户了
                all_customers = models.Customer.objects.filter(consultant=request.user)
        # 如果有数据就进行处理
        if all_customers:
            current_page_num = request.GET.get('page', default=1)
            # 每页显示5条
            per_page_counts = 5
            # 总共显示11个页码
            page_number = 11
            total_count = all_customers.count()
            page_obj = page.PageNation(request.path, current_page_num, total_count, request, per_page_counts,
                                       page_number)

            all_customers = all_customers.order_by('-pk')[page_obj.start_num:page_obj.end_num]
            ret_html = page_obj.page_html()
            return render(request, 'customers.html', {'all_customers': all_customers, 'ret_html': ret_html,'flag':self.flag})
       # 如果没查到数据的话,就返回一个空表格页面
        else:
            return render(request,'customers.html')

上面的代码是:公户与私户在同一个视图函数下的信息展示与搜索~~可以复习一下具体的逻辑。

主要还是看加粗的那部分,这是实现分页的视图函数的核心代码~~

另外,这里做了一个bug修复:如果搜不到数据的话,我给他返回一个空表格页面~

前端的渲染

前端的渲染十分简单!只需要在相应的位置加上标签就好了!

{{ ret_html|safe }}

~~

posted on 2019-06-17 07:21  江湖乄夜雨  阅读(189)  评论(0编辑  收藏  举报