stark组件(7):增加分页功能

效果图:

stark组件(7):增加分页功能

 

分页部分代码:

# 1.分页处理
all_count = self.model_class.objects.all().count()
query_params = request.GET.copy()  # 深copy
query_params._mutable = True  # query_params默认不可修改

pager = Pagination(
    current_page=request.GET.get('page'),
    all_count=all_count,
    base_url=request.path_info,
    query_params=query_params,
    per_page_data=self.per_page_data,
)
data_list = self.model_class.objects.all()[pager.start:pager.end]

context = {
    'data_list': data_list,
    'header_list': header_list,
    'body_list': body_list,
    'pager': pager,
}

 

 

一、分页功能

stark/utils/pagination.py

"""
分页器
"""


class Pagination(object):
    def __init__(self, current_page, all_count, base_url, query_params, per_page_data=20, display_page_number=11):
        """
        分页初始化
        :param current_page: 当前页码
        :param all_count: 数据库总条数
        :param base_url:  基础URL
        :param query_params:  Querydict对象,内部含所有当前URL的原条件
        :param per_page_data:  每页显示数据条数
        :param display_page_number:  页面上最多显示的页码数量
        """
        self.base_url = base_url
        try:
            self.current_page = int(current_page)
            if self.current_page <= 0:
                raise Exception()
        except Exception as e:
            self.current_page = 1

        self.all_count = all_count
        self.query_params = query_params
        self.per_page_data = per_page_data
        self.display_page_number = display_page_number
        real_page_number, remainder = divmod(self.all_count, self.per_page_data)
        if remainder != 0:
            real_page_number += 1
        self.real_page_number = real_page_number
        half_page_number = int(self.display_page_number / 2)
        self.half_page_number = half_page_number

    @property
    def start(self):
        """
        数据获取值起始索引
        :return:
        """
        return (self.current_page - 1) * self.per_page_data

    @property
    def end(self):
        """
        数据获取值结束索引
        :return:
        """
        return self.current_page * self.per_page_data

    def page_html(self):
        """
        生成HTML页码
        :return:
        """
        # 如果数据真实页码数小于11,则显示真实页码数
        if self.real_page_number < self.display_page_number:
            pager_start = 1
            pager_end = self.real_page_number
        else:
            # 真实页码数超过11
            if (self.current_page + self.half_page_number) > self.real_page_number:
                pager_start = self.real_page_number - self.display_page_number + 1
                pager_end = self.real_page_number
            else:
                pager_start = self.current_page - self.half_page_number
                pager_end = self.current_page + self.half_page_number

        page_list = []

        if self.current_page <= 1:
            prev_page = '<li><a href="#">上一页</a></li>'
        else:
            self.query_params['page'] = self.current_page - 1
            prev_page = '<li><a href="%s?%s">上一页</a></li>' % (self.base_url, self.query_params.urlencode())
        page_list.append(prev_page)

        for page_num in range(pager_start, pager_end + 1):
            self.query_params['page'] = page_num
            if self.current_page == page_num:
                show_page_num = '<li class="active"><a href="%s?%s">%s</a></li>' % (
                    self.base_url, self.query_params.urlencode(), page_num)
            else:
                show_page_num = '<li><a href="%s?%s">%s</a></li>' % (
                    self.base_url, self.query_params.urlencode(), page_num)
            page_list.append(show_page_num)

        if self.current_page == self.real_page_number:
            next_page = '<li><a href="#">下一页</a></li>'
        else:
            self.query_params['page'] = self.current_page + 1
            next_page = '<li><a href="%s?%s">下一页</a></li>' % (self.base_url, self.query_params.urlencode())
        page_list.append(next_page)
        page_str = ''.join(page_list)
        return page_str

 

二、Strak组件

from types import FunctionType

from django.urls import re_path
from django.utils.safestring import mark_safe
from django.shortcuts import HttpResponse, render, reverse

from stark.utils.pagination import Pagination


def get_choice_text(title, field):
    """
    对于Stark组件中定义列时,choice如果想要显示中文信息,调用此方法即可。
    :param title: 希望页面显示的表头
    :param field:  字段名称
    :return:
    """

    def inner(self, obj=None, is_header=None):
        if is_header:
            return title
        method = "get_%s_display" % field
        return getattr(obj, method)()
        # GENDER_CHOICES = ((MALE, '男'),(FEMALE, '女'),)
        # 对于choice字段,如果想获取获取第二个值,可以通过:对象.get_字段名_display()

    return inner


class StarkHandler(object):
    list_display = []
    per_page_data = 10

    def __init__(self, site, model_class, prev):
        self.site = site
        self.model_class = model_class
        self.prev = prev

    def display_edit(self, obj=None, is_header=None):
        """
        自定义页面显示的列(表头和内容)
        :param obj:
        :param is_header:
        :return:
        """
        if is_header:
            return '编辑'
        name = '%s:%s' % (self.site.namespace, self.get_edit_url_name,)
        return mark_safe('<a href="%s">编辑</a>' % reverse(name, args=(obj.pk,)))

    def display_delete(self, obj=None, is_header=None):
        if is_header:
            return '删除'
        name = '%s:%s' % (self.site.namespace, self.get_delete_url_name,)
        return mark_safe('<a href="%s">删除</a>' % reverse(name, args=(obj.pk,)))

    def get_list_display(self):
        """
        获取页面上应该显示的列,预留的自定义扩展,例如:以后根据用户的不同显示不同的列
        :return:
        """
        value = []
        value.extend(self.list_display)
        return value

    def list_view(self, request):
        """
        列表页面
        :param request:
        :return:
        """

        # 1.分页处理
        all_count = self.model_class.objects.all().count()
        query_params = request.GET.copy()  # 深copy
        query_params._mutable = True  # query_params默认不可修改

        pager = Pagination(
            current_page=request.GET.get('page'),
            all_count=all_count,
            base_url=request.path_info,
            query_params=query_params,
            per_page_data=self.per_page_data,
        )
        data_list = self.model_class.objects.all()[pager.start:pager.end]

        list_display = self.get_list_display()  # 会优先调用UserInfoHandler里的get_list_display()方法。
        # 2.1 处理表格的表头
        header_list = []
        if list_display:
            for field_or_func in list_display:
                if isinstance(field_or_func, FunctionType):
                    verbose_name = field_or_func(self, obj=None, is_header=True)
                else:
                    verbose_name = self.model_class._meta.get_field(field_or_func).verbose_name
                header_list.append(verbose_name)
        else:
            header_list.append(self.model_class._meta.model_name)  # 如果用户没有填写list_display,就显示表名

        # 2.2 处理表的内容
        body_list = []
        for obj in data_list:
            tr_list = []
            if list_display:
                for field_or_func in list_display:
                    if isinstance(field_or_func, FunctionType):
                        tr_list.append(field_or_func(self, obj, is_header=False))
                    else:
                        tr_list.append(getattr(obj, field_or_func))
            else:
                tr_list.append(obj)  # 如果用户没有填写list_display,就显示表对象,所以表类要定义__str__方法
            body_list.append(tr_list)

        context = {
            'data_list': data_list,
            'header_list': header_list,
            'body_list': body_list,
            'pager': pager,
        }

        return render(request, 'stark/data_list.html', context)

    def add_view(self, request):
        """
        添加页面
        :param request:
        :return:
        """
        return HttpResponse('添加页面')

    def edit_view(self, request, pk):
        """
        编辑页面
        :param request:
        :return:
        """
        return HttpResponse('编辑页面')

    def delete_view(self, request, pk):
        """
        删除页面
        :param request:
        :param pk:
        :return:
        """
        return HttpResponse('删除页面')

    def get_url_name(self, params):
        app_label, model_name = self.model_class._meta.app_label, self.model_class._meta.model_name
        if self.prev:
            return '%s_%s_%s_%s' % (app_label, model_name, self.prev, params)
        return '%s_%s_%s' % (app_label, model_name, params)

    @property
    def get_list_url_name(self):
        """
        获取列表页面URL的name
        :return:
        """
        return self.get_url_name('list')

    @property
    def get_add_url_name(self):
        """
        获取添加页面URL的name
        :return:
        """
        return self.get_url_name('add')

    @property
    def get_edit_url_name(self):
        """
        获取编辑页面URL的name
        :return:
        """
        return self.get_url_name('edit')

    @property
    def get_delete_url_name(self):
        """
        获取删除页面URL的name
        :return:
        """
        return self.get_url_name('delete')

    def get_urls(self):
        patterns = [
            re_path(r'^list/$', self.list_view, name=self.get_list_url_name),
            re_path(r'^add/$', self.add_view, name=self.get_add_url_name),
            re_path(r'^edit/(\d+)/$', self.edit_view, name=self.get_edit_url_name),
            re_path(r'^delete/(\d+)/$', self.delete_view, name=self.get_delete_url_name),
        ]

        patterns.extend(self.extra_urls())
        return patterns

    def extra_urls(self):
        return []


class StarkSite(object):
    def __init__(self):
        self._registry = []
        self.app_name = 'stark'
        self.namespace = 'stark'

    def register(self, model_class, handler_class=None, prev=None):
        """
        :param model_class: 是models中的数据库表对应的类。
        :param handler_class: 处理请求的视图函数所在的类
        :param prev: 生成URL的前缀
        :return:
        """

        if not handler_class:
            handler_class = StarkHandler
        self._registry.append(
            {'model_class': model_class, 'handler': handler_class(self, model_class, prev), 'prev': prev})

    def get_urls(self):
        patterns = []
        for item in self._registry:
            model_class = item['model_class']
            handler = item['handler']
            prev = item['prev']
            app_name, model_name = model_class._meta.app_label, model_class._meta.model_name
            if prev:
                patterns.append(
                    re_path(r'^%s/%s/%s/' % (app_name, model_name, prev,), (handler.get_urls(), None, None)))
            else:
                patterns.append(re_path(r'^%s/%s/' % (app_name, model_name,), (handler.get_urls(), None, None)))

        return patterns

    @property
    def urls(self):
        return self.get_urls(), self.app_name, self.namespace


site = StarkSite()

 

三、业务处理

from stark.service.core_func import site, StarkHandler, get_choice_text

from web import models


class DepartmentHandler(StarkHandler):
    list_display = ['title']


class UserInfoHandler(StarkHandler):
    per_page_data = 1
    list_display = [
        'name',
        get_choice_text('性别', 'gender'),
        get_choice_text('班级', 'classes'),
        'age', 'email', 'department',
        StarkHandler.display_edit,
        StarkHandler.display_delete,

    ]


site.register(models.Department, DepartmentHandler)  # 给部门的url增加了前缀:/stark/web/department/private/
site.register(models.UserInfo, UserInfoHandler)

 

四、模板渲染

{% extends 'layout.html' %}


{% block content %}
    <div class="custom-container">
        <table class="table table-bordered">
            <thead>
            <tr>
                {% for item in header_list %}
                    <th>{{ item }}</th>
                {% endfor %}
            </tr>
            </thead>
            <tbody>
            {% for row in body_list %}
                <tr>
                    {% for ele in row %}
                        <td>{{ ele }}</td>
                    {% endfor %}

                </tr>
            {% endfor %}
            </tbody>
        </table>

    <!-- 分页 -->
        <nav>
            <ul class="pagination">
                {{ pager.page_html|safe }}
            </ul>
        </nav>
    <!-- 分页结束 -->
    </div>
{% endblock content %}

 

上一篇:stark组件开发之URL分发和默认Handler


下一篇:CRM系统之stark组件流程分析