zoukankan      html  css  js  c++  java
  • day 68crm(5) 分页器的进一步优化,以及在stark上使用分页器,,以及,整理代码,以及stark组件search查询

    前情提要: 本节内容

        自定制分页器

          保存及查询记录

        代码整理,

        stark组件search 查询

           一:自定制分页器 page

      1:创建类 Pagination  # 自定制分页器

       _ _init_ _ 属性说明 

     

        2: 分页器的数据说明,以及简单的数据去除

      

      

     

         3 : 页面分析

    如果总数为100个,   设置每页8个数据      

    结果展示如下

     

      4: 展示每页的数据

    设置展示本页开始数据索引和本页结束数据索引

    由  3 可知 ,每页的展示情况

     

     5 :展示页码

    正常展示

    显示最后一页

    6 : 展示页码 情况

    主要分为4种情况

    7: 通过后台将前端页码展示进行渲染

    知识点补充:

    前面在源码中,request.GET 不允许进行修改值

    所以用copy 进行深拷贝.  

    在源码中的_ _ copy _ _ 允许进行修改

    这步操作的内容的意思的 当页码更改时,其他的参数不会被改动

    这个里面有两个参数, 

    7 >1:先获取前端数据

    7>2: 由于GET方法获取的内容不允许修改,所以进行深拷贝,为self.params, 此为字典形式

    7>3 :通过key:valuse 进行新增值 ,这样原来传过来的其他值就不会有问题

    7>4:

    self.params.urlencode() 
    这句可以把字典传话成字符串的格式, 如
    {'a':1 ,'b':2,'c':3} 转化成
    a=1&b=2&c=3

     结果:

    最后返回加好标签内容的字符串

    整段page 代码

    # -*- coding: utf-8 -*-
    # @Time    : 2019/4/17 15:17
    # @Author  : Endless-cloud
    # @Site    : 
    # @File    : page.py
    # @Software: PyCharm
    '''
             ┏┓  ┏┓+ +
            ┏┛┻━━━┛┻┓ + +
            ┃      ┃  
            ┃   ━   ┃ ++ + + +
            ████━████  ┃+
            ┃       ┃ +
            ┃   ┻   ┃
            ┃      ┃ + +
            ┗━┓   ┏━┛
              ┃   ┃           
              ┃   ┃ + + + +
              ┃   ┃    Code is far away from bug with the animal protecting       
              ┃   ┃ +     神兽保佑,代码无bug  
              ┃   ┃
              ┃   ┃  +         
              ┃    ┗━━━┓ + +
              ┃        ┣┓
              ┃       ┏┛
              ┗┓┓┏━┳┓┏┛ + + + +
               ┃┫┫ ┃┫┫
               ┗┻┛ ┗┻┛+ + + +
     '''
    
    
    class Pagination(object):  # 自定制分页器
        def __init__(self, request, current_page, all_data, per_page_num=2, max_page_count=11):
            """
    
            :param request: 当前操作界面的请求内容
            :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)  # 设定转化过数量总数通过len
            self.per_page_num = per_page_num  # 每页最多多少个
    
            all_pager, tmp = divmod(self.all_count, self.per_page_num)
            # all_pager  总页数
            # tmp  余数多少
            if tmp:  # 如果有余数
                all_pager += 1  # 那么页数加1
            self.all_pager = all_pager  # 总页数
            self.max_page_count = max_page_count  # 最多显示多少页
            self.max_pager_count_half = int((self.max_page_count - 1) / 2)  # 最大显示页对半分开数量
            self.request = request  # 获取当前操作的请求
    
            # request.GET ,获取的是querydict 源码中不予许修改
            import copy
            self.params = copy.deepcopy(self.request.GET)  # 从新深复制一遍GET内容,因为request不允许修改
            ## 获取前端得到内容,使得跳转的时候内容不会变更,即只更改page内容,其他内容不变更
            '''
            分析
            all_count =100  总计100个    per_page_num =10    每页使用
            current_page  当前操作页      start  开始        end  结束
            1                                  0               10
            2                                  10              20
            3                                  20              30
            
            
            all_count =100  总计100个    per_page_num =8    每页使用
            current_page  当前操作页      start  开始        end  结束
            1                                  0               8
            2                                  8               16
            3                                  16              24
            
            表达式          start =(current_page-1) *per_page_num 
                           end =(current_page * per_page_num)
                           
            
            '''
    
        @property
        def start(self):  # 展示数据页开始
            return (self.current_page - 1) * self.per_page_num  # 当前操作页-1 *每页个数
    
        @property
        def end(self):  # 展示数据也结尾
            return self.current_page * self.per_page_num  # 当前操作页*每页个数
    
        '''
               4种情况:
                   1:当操作页面不足显示最多页码个数
                   2:当操作页面内容显示在前11个内(不足减5)
                   3:当操作页面内容显示在后11个内(不足加5)
                   4:正常显示
    
               '''
    
        def page_html(self):   # 页码效果
            # 如果总页码  不足 11个:
            if self.all_pager <= self.max_page_count:  # 如果最大页数 小于设定的展示最多页数
                pageRange = range(1, self.all_pager + 1)  # 页码范围 1到最大页数  (1,当前最大页数+1)
            # 总页数 >11
            else:
                # 如果当前操作的页数小于11页的一半 5页
                if self.current_page <= self.max_pager_count_half:
                    pageRange = range(1, self.max_page_count + 1)  # 页码范围为1到12 (1,12)
                # 如果当前操作大于5个
                else:
                    # 当页码翻到最后
                    # 如果当前操作页加上5 大于最大页数
                    if (self.current_page + self.max_pager_count_half) > self.all_pager:
                        pageRange = range(self.all_pager - self.max_page_count + 1, self.all_pager + 1)
                        # 显示 (最大页数-允许显示虽多页数+1,最大页数+1)
                    else:
                        # 正常显示
                        pageRange = range(self.current_page - self.max_pager_count_half,
                                          self.current_page + self.max_pager_count_half + 1)
                        # 显示当前操作页-5 或者当前操作页+5
    
            # 构建分页页码的html
            # 直接传到前端用html的形式 ,达成自定制效果
            page_html_list = []  # 前端字符串 列表
            '''
            首页
            '''
            self.params["page"] = 1  # 修改request返回的内容
            first_page = '<nav aria-label="Page navigation"><ul class="pagination"><li><a href="?%s">首页</a></li>' % (
                self.params.urlencode(),
            )  # self.params.urlencode()  将字典转化成字符串 即将page=1 传入%s
            page_html_list.append(first_page)  # 将字符串加入到列表中
            self.params["page"] = self.current_page - 1  # 当前操作页 减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 当前操作页减1 替换
            page_html_list.append(prev_page)
            for i in pageRange:
                self.params["page"] = i  # 是当前page 展示的i
                if i == self.current_page:  # 如果i 等于当前操作页
                    temp = '<li claskk="active"><a href="?%s">%s</a></li>' % (self.params.urlencode(), i,)
                    # 如果当前操作页==i 跳转i页  显示数据i  #当前操作页标色
                else:
                    temp = '<li><a href="?%s">%s</a></li>' % (self.params.urlencode(), i,)  # 传入的是元祖
                    # 跳转i 页 ,显示数据i
                page_html_list.append(temp)
            self.params["page"] = self.current_page + 1  # 获取的params添加内容
            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   # 使page 等于最大页数
            last_page = '<li><a href="?%s">尾页</a></li> </ul></nav>' % (self.params.urlencode())
            page_html_list.append(last_page)
    
            return ''.join(page_html_list)  #直接返回整个字符串
    View Code

     二:stites 中的内容大整改  ,(把所有展示数据单独建立一个类)

    原:数据内容

    header_list = []  # 定制一个空别表
            for field_or_func in self.get_new_list_display():
                # 如果是多对多的
                if callable(field_or_func):
                    val = field_or_func(self, header=True)
                    header_list.append(val)
                    # header_list.append(field_or_func.__name__)
                # 如果是普通属性
                else:
    
                    if field_or_func == "__str__":
                        val = self.model._meta.model_name.upper()
                    else:
                        field_obj = self.model._meta.get_field(field_or_func)
                        val = field_obj.verbose_name  # 自定义属性名
    
                    header_list.append(val)
    
            # 构建展示数据
            new_data = []
            for obj in queryset:
                temp = []
                for field_or_func in self.get_new_list_display():
                    if callable(field_or_func):
                        val = field_or_func(self, obj)  # 获取函数返回值,传入obj进行从操作数据
    
                    elif not field_or_func == "__str__":
                        from django.db.models.fields.related import ManyToManyField
                        field_obj = self.model._meta.get_field(field_or_func)  # 获取模型对象
                        # 判断是否为多对多属性
                        if type(field_obj) == ManyToManyField:
                            raise Exception("list_display不能是多对多字段!")
                        # 判断是否有选择属性
                        if field_obj.choices:
                            val = getattr(obj, "get_%s_display" % field_or_func)()
                            # 调用这个方法,反射方法,调用方法获取对应的内容
                        else:
                            val = getattr(obj, field_or_func)
                            if field_or_func in self.list_display_links:
                                val = mark_safe("<a href='%s'>%s</a>" % (self.get_change_url(obj), val))
    
                    else:
                        val = getattr(obj, field_or_func)()
    
                    temp.append(val)
                    # print(">>>>>>>>>>>>",temp)
                new_data.append(temp)
    View Code

     今:整改部分

         1 :创建一个类

    在原来的地方通过实例对象调用内容

     2:函数说明

     3:调用说明

     requset ,当前操作请求  对应requset

    self ,当前操作自定义配置类, 对应config_obj

    quseryset   当前操作数据对应 queryset

    4:分页包调用以及配置

     4>1知识点:

    ruquset.GET.get("筛选内容",默认值=None)     

    即如果不写默认值则为空,这里写为1 即,没获取到时候为1

    4:>2 创建配置每页个数接口

       前提:设置接口

    4>3:最后返回的是分好页的数据(通过切片   [索引:索引])

     4>4:抬头部分

     4>5:展示数据

     5:前端做的修改

     

     前端效果

     

    # -*- coding: utf-8 -*-
    # @Time    : 2019/4/13 11:03
    # @Author  : Endless-cloud
    # @Site    : 
    # @File    : stites.py
    # @Software: PyCharm
    '''
             ┏┓  ┏┓+ +
            ┏┛┻━━━┛┻┓ + +
            ┃      ┃  
            ┃   ━   ┃ ++ + + +
            ████━████  ┃+
            ┃       ┃ +
            ┃   ┻   ┃
            ┃      ┃ + +
            ┗━┓   ┏━┛
              ┃   ┃           
              ┃   ┃ + + + +
              ┃   ┃    Code is far away from bug with the animal protecting       
              ┃   ┃ +     神兽保佑,代码无bug  
              ┃   ┃
              ┃   ┃  +         
              ┃    ┗━━━┓ + +
              ┃        ┣┓
              ┃       ┏┛
              ┗┓┓┏━┳┓┏┛ + + + +
               ┃┫┫ ┃┫┫
               ┗┻┛ ┗┻┛+ + + +
     '''
    
    from django.urls import path, re_path
    
    from app01.models import *
    from django.shortcuts import HttpResponse, render, redirect
    
    from django.utils.safestring import mark_safe
    from django.urls import reverse
    
    
    class ShowList(object):  #
        def __init__(self, request, config_obj, queryset):
            self.request = request # 接收请求
            self.config_obj = config_obj #接收自定义配置类
            self.queryset = queryset  #接收数据
            self.pager_queryset = self.get_pager_queryset() # 实例分页对象获取内容
    
        def get_pager_queryset(self):
            from stark.utils.page import Pagination  # 导入自己写的分页包
            current_page = self.request.GET.get("page", 1)  # 当前操作页
            self.pagination = Pagination(self.request, current_page, self.queryset,
                                         per_page_num=self.config_obj.per_page_num or 5)
            queryset = self.queryset[self.pagination.start:self.pagination.end]
            return queryset
    
        def get_header(self):
            header_list = []  # 定制一个空别表
            for field_or_func in self.config_obj.get_new_list_display():  # 替换成config_obj 代用,self 代表原自定义配置类
                # 如果是多对多的
                if callable(field_or_func):
                    val = field_or_func(self, header=True)
                    header_list.append(val)
                    # header_list.append(field_or_func.__name__)
                # 如果是普通属性
                else:
    
                    if field_or_func == "__str__":
                        val = self.config_obj.model._meta.model_name.upper()
                    else:
                        field_obj = self.config_obj.model._meta.get_field(field_or_func)
                        val = field_obj.verbose_name  # 自定义属性名
    
                    header_list.append(val)
            return header_list   #f返回前端的内容
        def get_body(self):
    
            # 构建展示数据
            new_data = []
            for obj in self.pager_queryset:
                temp = []
                for field_or_func in self.config_obj.get_new_list_display():
                    if callable(field_or_func):
                        val = field_or_func(self.config_obj, obj)  # 获取函数返回值,传入obj进行从操作数据
                        # self  统一换成self.config_obj
                    elif not field_or_func == "__str__":
                        from django.db.models.fields.related import ManyToManyField
                        field_obj = self.config_obj.model._meta.get_field(field_or_func)  # 获取模型对象
                        # 判断是否为多对多属性
                        if type(field_obj) == ManyToManyField:
                            raise Exception("list_display不能是多对多字段!")
                        # 判断是否有选择属性
                        if field_obj.choices:
                            val = getattr(obj, "get_%s_display" % field_or_func)()
                            # 调用这个方法,反射方法,调用方法获取对应的内容
                        else:
                            val = getattr(obj, field_or_func)
                            if field_or_func in self.config_obj.list_display_links:
                                val = mark_safe("<a href='%s'>%s</a>" % (self.config_obj.get_change_url(obj), val))
    
                    else:
                        val = getattr(obj, field_or_func)()
    
                    temp.append(val)
                    # print(">>>>>>>>>>>>",temp)
                new_data.append(temp)
    
            return new_data #返回前端数据部分
    class ModelStark(object):
        '''
        默认配置类
        '''
        list_display = ("__str__",)
        list_display_links = []  # 设置默认为空
        model_form_class = None  # 设置默认为无
        per_page_num=None  #设置接口
        search_fields = []  #创建search_fidels接口
        search_val = None  # 默认让search_val的值为none
        def __init__(self, model):
            self.model = model
            self.model_name = self.model._meta.model_name
            self.app_label = self.model._meta.app_label
    
    
            # 反向解析当前访问表的增删改查URL
    
        def get_list_url(self):
            # 反向解析当前表的删除的URL
            list_url = reverse("%s_%s_list" % (self.app_label, self.model_name))
            return list_url
    
        def get_add_url(self, obj=None):
            # 反向解析当前表的删除的URL
            add_url = reverse("%s_%s_add" % (self.app_label, self.model_name))
            return add_url
    
        def get_delete_url(self, obj):
            # 反向解析当前表的删除的URL
            delete_url = reverse("%s_%s_delete" % (self.app_label, self.model_name), args=(obj.pk,))
            return delete_url
    
        def get_change_url(self, obj):
            # 反向解析当前表的change的URL
            change_url = reverse("%s_%s_change" % (self.app_label, self.model_name), args=(obj.pk,))
            return change_url
    
        def get_new_list_display(self):
            temp = []
            temp.extend(self.list_display)  # 继承原来的列表内容
            temp.append(ModelStark.show_editbtn)  # 注意传过来的是属性
            temp.append(ModelStark.show_delbtn)  # 注意传过来的是属性
            temp.insert(0, ModelStark.show_checkbox)
            # temp.insert(1,self.show_checkbox())
            # 同上不加括号,把方法名加入到列表方便掉用
            return temp
    
        def show_checkbox(self, obj=None, header=False):
            # 展示选择列
            if header:
                return mark_safe("<input type='checkbox'>")
            return mark_safe("<input type='checkbox'>")
    
        def show_delbtn(self, obj=None, header=False):
            if header:
                return "删除"
    
            return mark_safe("<a href='%s'>删除</a>" % self.get_delete_url(obj))
    
        def show_editbtn(self, obj=None, header=False):
            if header:
                return "编辑"
            return mark_safe("<a href='%s'>编辑</a>" % self.get_change_url(obj))
    
        def get_search_condition(self, request):
            val = request.GET.get("q")  # 获取name q的内容
    
            from django.db.models import Q  # 导入Q 包 .进行或操作
            q = Q()  # 实例一个Q 对象
            if val:# 如果进行了查询操作
                self.search_val = val
                q.connector = "or"  # 更改q为或操作
                for field in self.search_fields:  # ["title","price"] # 从接口中拿字段
                    print(field)
                    # queryset=queryset.filter(Q(title__contains=val)|Q(price__contains=val))
                    q.children.append((field + "__contains", val))
                    #  利用小q进行模糊查询,和拼接
                    # "__contains 模糊查询" 即 title__contains=val  查询
            else:
                self.search_val = None
    
            return q
    
        def list_view(self, request):
            # print(self)  # 当前访问模型表对应的配置类对象
            # print(self.model)  # 当前访问模型表
            queryset = self.model.objects.all()
            print("+>>>>>>>", queryset)
            # 构建表头
            queryset=queryset.filter(self.get_search_condition(request))
            show_list = ShowList(request, self, queryset)
            # 当前请求 ,当前操作的自定制配置类,当前所有数据
            table_name = self.model._meta.verbose_name
            add_url = self.get_add_url()
            # print("<<<<<<<<<<<",new_data)
            return render(request, "stark/list_view.html", locals())
    
            # data = self.model.objects.all()
            # print(data)
            # print("-------",self.list_display)
            # data_list=[]
            # dict1={}
            # for obj in data:
            #     lis =[]
            #     for msg in self.list_display:
            #         lis.append(getattr(obj,msg))
            #     data_list.append(lis)
            # print("jjjjjjjjj",data_list)
            # return render(request, 'stark/list_view.html', {
            #     "data_list":data_list,
            #     "list_display":self.list_display
            # })
    
        def get_model_form(self):  # 创建获取model_form 内容函数
            from django.forms import ModelForm  # 导入包
            class BaseModelForm(ModelForm):  # 创建modelform类,继承modelform
                class Meta:  # 创建可调用内容
                    model = self.model  # 导入当前操作模型对象
                    fields = "__all__"  # 获取全部
    
            return self.model_form_class or BaseModelForm  # 如果有内容就传入内容,没有就走默认的Base的
            # 有的时候需要重新写class BasemodelForm类并继承他
    
        def add_view(self, request):  # 视图函数add_view
            BaseModelForm = self.get_model_form()  # 通过get_model_form运行获取类
            if request.method == "GET":
                form_obj = BaseModelForm()  # 实例化对象获取内容
                return render(request, "stark/add_view.html", locals())  # 传到前端内容(属性)
            else:
                form_obj = BaseModelForm(request.POST)  # 向渲染的模型类中加入数据
                if form_obj.is_valid():  # 判断接收数据是否可用
                    form_obj.save()  # 将数据保存到数据库
                    return redirect(self.get_list_url())  # 跳转
                else:
                    return render(request, "stark/add_view.html", locals())
    
        def change_view(self, request, id):  # 创建change_view路由 ,传入request,id,通过反向解析获取id
            BaseModelForm = self.get_model_form()  # 通过方法获取modelform类
            edit_obj = self.model.objects.filter(pk=id).first()  # 通过id获取当前操作对象
            if request.method == "GET":
                form_obj = BaseModelForm(instance=edit_obj)  # 通过instance参数,进行控制为传入对象可以到前端进行渲染
                return render(request, "stark/change_view.html", locals())
            else:
                form_obj = BaseModelForm(request.POST, instance=edit_obj)  # 接收前端内容,instance对象,是内容进行覆盖
                if form_obj.is_valid():
                    form_obj.save()  # 数据保存
                    return redirect(self.get_list_url())
                else:
                    return render(request, "stark/change_view.html", locals())
    
        def delete_view(self, request, id):  # 接收反向解析传过来的id
            if request.method == "POST":
                self.model.objects.filter(pk=id).delete()  # 接收id 删除主键
                return redirect(self.get_list_url())  # 跳转
            list_url = self.get_list_url()  # 把展示界面传过去.方便用户取消
    
            return render(request, "stark/delete_view.html", locals())  # 新建删除html
    
        @property
        def get_urls(self):
            temp = [
                path("", self.list_view, name="%s_%s_list" % (self.app_label, self.model_name)),
                path("add/", self.add_view, name="%s_%s_add" % (self.app_label, self.model_name)),
                re_path("(d+)/change/", self.change_view, name="%s_%s_change" % (self.app_label, self.model_name)),
                re_path("(d+)/delete/", self.delete_view, name="%s_%s_delete" % (self.app_label, self.model_name)),
            ]
    
            return (temp, None, None)
    
    
    class StarkSite:
        '''
        stark全局类
        '''
    
        def __init__(self):
            self._registry = {}
    
        def register(self, model, admin_class=None, **options):
            admin_class = admin_class or ModelStark
            self._registry[model] = admin_class(model)
    
        def get_urls(self):
            #  动态为注册的模型类创建增删改查URL
            temp = []
            # {Book:ModelAdmin(Book),Publish:ModelAdmin(Publish)}
            for model, config_obj in self._registry.items():
                # print("---->", model, config_obj)
                model_name = model._meta.model_name
                app_label = model._meta.app_label
                temp.append(
                    path("%s/%s/" % (app_label, model_name), config_obj.get_urls)
                )
    
            '''
               path("stark/app01/book",self.list_view)
               path("stark/app01/book/add",self.add_view)      
               path("stark/app01/publish",self.list_view)
               path("stark/app01/publish/add",self.add_view)
    
    
            '''
    
            return temp
    
        @property
        def urls(self):
            return self.get_urls(), None, None
    
    
    site = StarkSite()
    View Code

     三:stark 中的search内容

      知识点: django中的Q()使用

      实例化Q 以后可以进行更改内容且 通过字符串进行修改

     接口内容

    注册接口内容

    1 :前端代码内容

    设置name=q 进行from 表单数据操作 

    通过if 

    进行判断如果有配置search_fidleds 接口则显示出搜索框,否则

    不显示搜索框

     2:stites 数据

    _ _contains  进行数据模糊查询

     3: 数据通过search 进行数据过滤

     效果展示:

    通过''阿'' 进行 搜索

  • 相关阅读:
    January 25th, 2018 Week 04th Thursday
    January 24th, 2018 Week 04th Wednesday
    January 23rd, 2018 Week 04th Tuesday
    January 22nd, 2018 Week 04th Monday
    January 21st, 2018 Week 3rd Sunday
    January 20th, 2018 Week 3rd Saturday
    January 19th, 2018 Week 3rd Friday
    January 18th, 2018 Week 03rd Thursday
    January 17th, 2018 Week 03rd Wednesday
    January 16th, 2018 Week 03rd Tuesday
  • 原文地址:https://www.cnblogs.com/baili-luoyun/p/10724564.html
Copyright © 2011-2022 走看看