Day68 crm项目stark组件之自定义分页功能,保留数据功能,search查询功能

10.stark组件自定义一个分页功能

在stark文件夹下建一个新的文件夹utils文件夹,建一个page.py文件:

class Pagination(object):

    def __init__(self, request, current_page, all_data, per_page_num=2, max_page_count=11):
        """
        封装分页相关数据
        :param current_page: 当前页
        :param all_data:    分页数据中的数据总条数
        :param per_page_num: 每页显示的数据条数
        :param max_page_count:  最多显示的页码个数
        """

        # 先对传进来的参数进行一个初步过滤
        try:
            current_page = int(current_page)  # 如果传过来的不是字符串,设置为第一页
        except Exception as e:
            current_page = 1
        if current_page < 1:
            current_page = 1

        self.current_page = current_page
        self.all_count = len(all_data)
        self.per_page_num = per_page_num

        # 总页码, 对总页码数进行一个处理
        all_pager, tmp = divmod(self.all_count, per_page_num)  # 对一个数取余,如果有余数,增多加一页
        if tmp:
            all_pager += 1
        self.all_pager = all_pager
        self.max_page_count = max_page_count
        self.max_page_count_half = int((max_page_count - 1) / 2)

        self.request = request
        import copy
        self.params = copy.deepcopy(self.request.GET)

    def page_html(self):
        # 如果总页码数大于11
        # if self.all_pager > 11:   写死了
        if self.all_pager > self.max_page_count:
            # 当前页如果小于页面上最多显示(11-1)/2个页码,小于5
            if self.current_page <= self.max_page_count_half:
                pageRange = range(1, self.max_page_count + 1)
            # 当前页大于5
            else:
                if (self.current_page + self.max_page_count_half) >= self.all_pager:
                    pageRange = range(self.all_pager - self.max_page_count + 1, self.all_pager)
                else:
                    pageRange = range(self.current_page - self.max_page_count_half,
                                      self.current_page + self.max_page_count_half + 1)
        else:  # 小于11页的时候
            pageRange = range(1, self.all_pager + 1)

        # 构建分页页码的html
        page_html_list = []
        # 第一步:设置 首页按钮,也就是该按钮返回第一页
        self.params['page'] = 1
        first_page = '<nav aria-label="Page navigation"><ul class="pagination"><li><a href="?%s">首页</a></li>' % (
            self.params.urlencode(),)  # 知识点  request.GET.get 里 urlencode方法,将query_dict 转化成 a=1&b=2 这种字符串
        page_html_list.append(first_page)  # 加入列表

        # 第二步: 设置上一页按钮
        self.params["page"] = self.current_page - 1
        if self.current_page <= 1:
            prev_page = '<li class="disabled"><a href="#">上一页</a></li>'  # 第一页的时候上一页不可点击
        else:
            prev_page = '<li><a href="?%s">上一页</a></li>' % (self.params.urlencode(),)
        page_html_list.append(prev_page)

        # 第三步设置分页数字按钮,当前页设置深色
        for i in pageRange:
            self.params['page'] = i
            if i == self.current_page:
                temp = '<li class="active"><a href="?%s">%s</a></li>' % (self.params.urlencode(), i,)
            else:
                temp = '<li><a href="?%s">%s</a></li>' % (self.params.urlencode(), i,)
            page_html_list.append(temp)

        # 第四步 设置下一页
        self.params['page'] = self.current_page + 1
        if self.current_page >= self.all_pager:
            next_page = '<li class="disabled"><a href="#">下一页</a></li>'  # 不可点击
        else:
            next_page = '<li><a href="?%s">下一页</a></li>' % (self.params.urlencode(),)
        page_html_list.append(next_page)

        # 第五步 设置尾页
        self.params["page"] = self.all_pager
        last_page = '<li><a href="?%s">尾页</a></li> </ul></nav>' % (self.params.urlencode())
        page_html_list.append(last_page)

        return ''.join(page_html_list)

    # 利用 start 和end 值来切割列表。例如数据列表为 data ,, data[0:10]切割出十条
    @property
    def start(self):
        return (self.current_page - 1) * self.per_page_num

    @property
    def end(self):
        return self.current_page * self.per_page_num

    '''
     all_count=100    per_page_num =10 

     current_page        start    end
          1                 0      10
          2                 10     20
          3                 20     30

     表达式:    start= (current_page-1)*per_page_num    end =current_page* per_page_num

    '''

 

 

11.分页功能之数据保留功能

可以看到我们在原来的基础上多传了一个参数params,这个参数就是当前页的request.GET,这是一个QueryDict的数据类型(和字典类似),我们取到他后,发现无法直接进行修改,这是应为QueryDict默认是不让修改的,需要修改mutable参数为True才能修改

修改前我们为了防止直接修改request.GET而造成后面的影响,所以先用深拷贝拷贝一份数据,再进行修改,修改时,我们将pape改为当前页的页码,再利用QueryDict的urlencode方法将字典类型的数据转换成a=1&b=2类型的字符串数据,然后在生成页码a标签时在a标签的href属性后面加上生成的字符串,这样我们点击页面跳转时就可以保留url上的数据了

分页组件的使用,在crm项目中使用:

    def list_view(self, request):
        """
        展示页面
        :param request:
        :return:
        """
        queryset = self.model.objects.all()
        add_url = self.get_add_url()  # 传到前端按钮,跳转到添加页面
        table_name = self.model._meta.verbose_name  # 或许每张表的自定义表名

        # 使用自定制分页器
        current_page = request.GET.get("page", 1)
        all_data = self.model.objects.all()
        pagination = Pagination(request, current_page, all_data, per_page_num=5)
        queryset = self.model.objects.all()[pagination.start: pagination.end]

前端页面:调用page_html函数即可

        <div class="pull-right">
            {{ pagination.page_html|safe }}
        </div>

 

编辑页面实现url数据保留

上面我们在写编辑页面时并没有考虑保留页面url上的数据,现在我们增加上这个功能

首先点击编辑按钮进入编辑页面时我们需要保留url上的数据,这就需要对编辑按钮这个a标签的href属性进行修改,在后面加上url上要保留的数据,同时,为了让加上的数据不和编辑页面可能有的数据冲突,所以我们单独定义一个list_filter键来存放这些数据

class Pagination(object):

def __init__(self, request, current_page, all_data, per_page_num=2, max_page_count=11):
      import copy
      self.params = copy.deepcopy(self.request.GET)  # 复制一份 ?page=2&a=1&b=2 ,这里一定要用deepcopy,_mutable = True
      # print(self.params)
      # < QueryDict: {'page': ['1'], 'a': ['1'], 'b': ['2']} >
      first_page = '<nav aria-label="Page navigation"><ul class="pagination"><li><a href="?%s">首页</a></li>' % (
          self.params.urlencode(),)  # 知识点  request.GET.get 里 urlencode方法,将query_dict 转化成 a=1&b=2 这种字符串

 

 12.seach 查询功能

使用admin时我们能定义一个search_fields列表来生成一个查询框,可以根据列表中的字段进行模糊查询

我们也来定义这么一个参数

class ModelStark(object):
    list_display = ["__str__", ]

    model_form_class = None

    list_display_links = []

    search_fields = []

默认让他为一个空列表,当用户定义了值时,我们就需要在页面生成一个搜索框,并且根据模糊查询得到需要的数据展示到页面上,这里需要注意如果用户在列表中定义了多个字段,那么多个字段查询时应该是或的关系  or

Q查询利用字符串进行查询的方式

在查询时由于是或的关系所以我们要用到Q查询,但是我们之前使用Q查询时都是直接使用的字段名,现在我们只能拿到字段名的字符串,所以需要用Q查询的另外一种方式

    def get_search_condition(self, request):
        val = request.GET.get("q")   # 获取前段页面的get请求时传过来的参数,input 里面有个name=‘q’

        from django.db.models import Q
        query = Q()  
        if val():
            self.search_val = val
            query.connector = "or"  # 设置为or关系
            for field in self.search_fields:
                # queryset=queryset.filter(Q(title__contains=val)|Q(price__contains=val))
                query.children.append((field + "__contains", val))  #  price__contains, title__contains 模糊查询 ,
        else:
            self.search_val = None  # 清空原数据
        return query

先生成一个Q对象,设置为或的关系,然后通过循环将要查询的字段的字符串和查询关键字以元组的形式添加到Q对象中,这里要注意,由于是模糊查询,我们在字段字符串后拼接了__contains

    def list_view(self, request):
        """
        展示页面
        :param request:
        :return:
        """
        queryset = self.model.objects.all()
        add_url = self.get_add_url()  # 传到前端按钮,跳转到添加页面
        table_name = self.model._meta.verbose_name  # 或许每张表的自定义表名

        # search过滤
        queryset = queryset.filter(self.get_search_condition(request))

前端页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    <style>
        .navbar-collapse {
            border-color: #101010;
        }
    </style>
</head>
<body>

<div id="navbar" class="navbar-collapse collapse">
    <a class="navbar-brand" href="#">查看数据</a>
</div>


<div class="container">
    <div class="row">
        <a class='btn btn-primary' href="{{ add_url }}">添加{{ table_name }}</a>
        {% if showlist.config_obj.search_fields %}
            <form action="" method="get" class="navbar-form navbar-right">
                <div class="input-group pull-right" style="width: 400px">
                    <input value="{{ showlist.config_obj.search_val|default:'' }}" type="text" name="q"
                           class="form-control" placeholder="Search for...">
                    <span class="input-group-btn">
                        <button class="btn btn-default">Search!</button>
                      </span>
                </div>
            </form>
        {% endif %}
        <table class="table table-striped table-hover">
            <thead>
            <tr>
                {% for item in showlist.get_header %}
                    <th>{{ item }}</th>
                {% endfor %}
            </tr>

            </thead>
            <tbody>
            {% for item in showlist.get_body %}
                <tr>
                    {% for info in item %}
                        <td>{{ info }}</td>
                    {% endfor %}
                </tr>
            {% endfor %}
            </tbody>
        </table>
        <div class="pull-right">
            {{ showlist.pagination.page_html|safe }}
        </div>
    </div>
</div>

</body>
</html>

 

posted @ 2019-04-17 16:10  addit  Views(65)  Comments(0)    收藏  举报