django-admin效果仿写,stark自定义search以及分页显示,url参数保留

 

search模糊查询功能搞定,

我们的form表单里面action如果为空,那么不论我们的method请求是get还是post,我们的url都是走的同一个,这一点需要记住

还有我们的url里面有参数:在?后面加上的=左右两边都是键值对的方式发送的数据请求,我们的url里面的这样的键值对参数是需要保存的,不论我们以后跳转到哪里去,都要把这些参数携带着,这里就需要我们使用一个知识点

from django.http import QueryDict

在这个QueryDict里面封装的方法,可以帮我们获取url里面的键值对参数,然后我们用它取出来即可,就是在取值的过程中,有一点小障碍,在内部源码级别,我们这里有一个参数,

mutable=False,这个意思是我们不能够改动这个键值对,我们在使用的时候给这个键值对赋值就把它改成True就可以了,然后使用这个QueryDict就可以把我们url里面的键值对保存,然后在跳转的时候就会携带着他们了

https://i.cnblogs.com/EditArticles.aspx?postid=8585099

 

 

----
    Changelist类-----服务展示页面
    search模糊查询
    action批量处理    
上节回顾:
    基于modelForm实现
     添加页面
     编辑页面
今日内容:
----跳转页面时如何保留搜索条件
    分页组件   
    知识点1:QueryDict
            from django.http import QueryDict
            print(request.GET)  #    <QueryDict: {}> # <QueryDict: {'id': ['1']}>
            request.GET._mutable=True
            request.GET["a"]=1  # <QueryDict: {'id': ['1'], 'a': [1]}>
            # urlencode 编码   "a=1&b=2$c=3"
            print(request.GET.urlencode()) # "id=1&a=1"
            print(request.GET)
            #创建QueryDict
            qd=QueryDict(mutable=True)
            qd["name"]="yuan"
            if self.all_pager<11:
                 begin=1
                 end=all_pager+1 
            else:
                if self.current_page<5:
                    begin=1
                    end=11+1
                    
                elif self.current_page+5>self.all_pager:
                    begin=self.all_pager-10
                    end=self.all_pager+1
                    
                else:
                     begin=self.current_page-5
                     end=self.current_page+5+1
            
         
    for i in range(begin,end):
       s="<li><a href=''>i<a></li>"
    编辑按钮,删除按钮  
    知识点2:
    
          form    action=http://127.0.0.1:8000/stark/app01/book/?a=1&b=2   method="get"  
          
          GET请求:
               request.GET    {"a":1,"b":2}
               request.POST   {}               
          form    action=http://127.0.0.1:8000/stark/app01/book/?a=1&b=2   method="post"
          
                <input type="text" name="user" value="123">               
               
          POST请求:
               request.GET    {"a":1,"b":2}
               request.POST   {"user":"123"}    
 Changelist类-----服务展示页面
 
 search模糊查询
 ----------
 
 action
 filter
 pop(js)

 

 

  1 from django.conf.urls import url
  2 from django.shortcuts import render, redirect, reverse
  3 from django.utils.safestring import mark_safe
  4 from django.forms import ModelForm  # 这个ModelForm里面封装了很强大的功能,要把源码过一遍
  5 
  6 
  7 class StandLi(object):
  8     def __init__(self, config, request, queryset):
  9         """
 10         :param config: 它就是我们下面的类ModelSubject所传过来的它的self实例对象,
 11         我们在这里要使用那些方法和变量就需要把它的这个实例对象拿过来,否则如下搬过来的代码块都会失效
 12         :param request: 我们这个类是在下面的ModelSubject里面调用然后在那里实例化出来的对象,所以这个request是它传过来的
 13         :param queryset: 同上,这个queryset也是ModelSubject所传过来的参数,供下面的代码调用
 14         """
 15         self.config = config
 16         self.request = request
 17         self.queryset = queryset
 18 
 19         # 生成分页器
 20         path = self.request.path_info
 21         params = self.request.GET
 22         page_num = request.GET.get('page', 1)  # 如果没有找到page,就返回1,也就是第一页
 23         from file.utensil.page import MyPage
 24         count = queryset.count()
 25         page = MyPage(page_num, count, path, params)
 26         self.pagination = page
 27         data_list = self.queryset[page.start:page.end]
 28         self.data_list = data_list
 29         # page_html = page.page_html()  # 这里我们可以把page_html方法直接在前端HTML模板里面引用
 30 
 31     def get_header(self):
 32         # 生成表头数据
 33         # ['id','title','price',edit]
 34         header_list = []
 35         for field in self.config.get_list_display():
 36             if callable(field):
 37                 ret = field(self, is_header=True)
 38                 header_list.append(ret)
 39             else:
 40                 if field == '__str__':  # 这里是判断我们的list_display列表里面是否有我们自定义传入的值,如果没有的话,
 41                     # 就是直接等于我们在静态属性里面设定的那个默认的'__str__',也就是说如果这一步判断成立,
 42                     # 那么就证明我们的用户没有自定义展示的字段,我们就需要自己给浏览器一个字段去展示,那个字段就是我们这里所设定的那个大写的表名
 43                     header_list.append(self.config.model._meta.model_name.upper())  # 我们这里的操作是
 44                 else:
 45                     obj = self.config.model._meta.get_field(field)  # 我们的list_display里面是一个个的字符串,
 46                     # 把字符串放到get_field里面来可以把我们的字符串转换成类对象,
 47                     header_list.append(obj.verbose_name)  # 我们这里的verbose_name在model里面是内置方法,
 48                     # 我们的verbose_name本质上是对我们的字段进行描述的,比如我们的book里面的title可以在字段约束里面设
 49                     # verbose_name='书名',类似于这样,把它变成中文,然后我们在前端HTML模板里面渲染的时候就可以渲染出来中文了,
 50                     # 而不是使用默认的英文,当然了我们如果不设置verbose_name的值那么就使用默认的title作为字段名传到浏览器
 51 
 52         return header_list
 53 
 54     def get_body(self):
 55         # 生成表单数据列表(我们把这个函数挪到上面这个类里面来之后,把循环遍历的数据改动了,之前是把当前表格的数据取出来之后就直接遍历它,
 56         # 后来我们有了搜索功能,那么就不能遍历表格里面的所有数据了,需要把我们过滤查询出来的数据给遍历出来
 57         # ret = self.config.model.objects.all().count()
 58         # print('self.list_display', self.list_display)
 59         data_list = []
 60         for obj in self.data_list:  # 我们遍历这个queryset集合得到的obj是它的每一个对象
 61             temp = []
 62             for field in self.config.get_list_display():  # 我们遍历list_display得到每一个字符串
 63                 if callable(field):
 64                     # res = field(obj)  # @@@更上面的特殊标识的代码块相呼应
 65                     res = field(self.config, obj)  # &&& 这里跟上面同样标识的代码块相呼应的,上面我们使用的类名去调用函数名,
 66                     # 得到的是一个函数,这里就是给所调用的函数传参的,self,和obj都是我们传给函数的参数;
 67                     # 如果我们使用self这个对象去调用函数名的方法的话,就不需要再传一个self作为参数进去了,我们两种方法都可以,需要对应上即可
 68                 else:
 69                     res = getattr(obj, field)  # 使用getattr方法去判断该对象是否具有,field属性方法,
 70                     # getattr里面需要两个参数(类对象,字符串属性方法)
 71                     if field in self.config.list_display_links:  # 我们这里是判断表单里面的字段是否在links表格里面被自定义作为可跳转标签,
 72                         # 如果答案是肯定的,那么我们就需要把a标签给拼出来
 73                         res = self.config.get_link_tag(obj, res)
 74                 temp.append(res)
 75             data_list.append(temp)
 76 
 77         # print('data_list', data_list)
 78 
 79         """
 80         我们最终得到的数据类型是如下格式:列表套着列表
 81         [
 82         使用orm语句得到的每一个类对象,有几个表格就有几个对象
 83         ]
 84         list_display=['id','title',]
 85         [
 86         [1,'python',<a>编辑</a>],
 87         [2,'java',<a>编辑</a>],
 88         ]
 89         """
 90         return data_list
 91 
 92 
 93 class ModelSubject(object):
 94     """
 95     我们在这里模拟admin源码里面的ModelAdmin,
 96     """
 97     list_display = ["__str__"]  # 我们在这里给空列表里面加上"__str__",它就相当于是一个默认值,
 98     model_form_class = None  # 为下面我们判断用户是否有自定义ModelForm校验方式而做铺垫
 99     search_fields = []
100     list_display_links = []  # 为我们后面用户是否有自定义可跳转字段做铺垫
101     # 就像我们的函数里面有默认值的参数一样,如果有传参就使用我们的自定义传参,如果没有传参就使用我们默认的参数也就是这个字符串,
102     # 这里是为了给我们后面的代码做铺垫,我们的目的是在我们的数据展示页面里面默认就会把复选框和编辑还有删除按钮都加上,
103     # 在这里把空列表里面添加上一个默认的字符串,是为了我们后面往该列表里面添加默认固定数据也就是复选框和编辑删除按钮做铺垫
104 
105     # 静态内置方法
106     def __init__(self, model, site):
107         self.model = model  # 当我们生成一个实例化对象的时候需要把model这个参数传进来,
108         # 必须要传,它是位置参数,然后我们所传入的那个model就是我们在models.py里面定义的每一个表名也就是类名
109         self.site = site
110         self.namespace = '{}_{}'.format(self.model._meta.app_label, self.model._meta.model_name)
111         # self.app_model_name = (self.model._meta.app_label, self.model._meta.model_name)  # 这里写得跟上面一句是一样的效果,
112         # 这里调用的时候需要有两个%s,因为这里是一个元祖,而我们上面的namespace是一个字符串,不是一个元祖,所以只需要一个%s即可,调用的时候就这点区别
113     # 我们这里的namespace是因为会频繁使用到所以就把它作为一个内置静态属性写入到这里,其他地方如果要调用它就直接使用self.namespace即可
114     # .format的方法:'{}_{}'.format(a,b)
115 
116     # 获取展示页面的url
117     def get_stand_url(self):
118         stand_url = reverse('%s_standlist' % self.namespace)
119         return stand_url
120 
121     # 获取编辑页面的url
122     def get_edit_url(self, obj):
123         edit_url = reverse('%s_edit' % self.namespace, args=(obj.pk,))
124         return edit_url
125 
126     # 获取删除页面的url
127     def get_dele_url(self, obj):
128         dele_url = reverse('%s_dele' % self.namespace, args=(obj.pk,))
129         return dele_url
130 
131     # 获取增加页面的url
132     def get_add_url(self):
133         add_url = reverse('%s_add' % self.namespace)
134         return add_url
135 
136     # 展示页面默认附带的编辑按钮
137     def edit(self, obj=None, is_header=False):
138         if is_header:
139             return '操作'
140         return mark_safe('<a href="%s">编辑</a>' % reverse('%s_edit' % self.namespace, args=(obj.pk,)))
141 
142     # 展示页面默认附带的删除按钮
143     def dele(self, obj=None, is_header=False):
144         if is_header:
145             return '删除'
146         return mark_safe("<a href='%s'>删除</a>" % reverse('%s_dele' % self.namespace, args=(obj.pk,)))
147 
148     # 展示页面附带的默认复选框
149     def checkbox(self, obj=None, is_header=False):
150         if is_header:
151             return mark_safe("<input id='action-toggle' type='checkbox'>")
152         return mark_safe("<input type='checkbox' values='%s'>" % obj.pk)
153 
154     # 展示页面默认显示按钮被存放的列表
155     def get_list_display(self):
156         new_li = []
157         new_li.extend(self.list_display)  # 我们这里的extend是把它后面的列表里面的数据都取出来放到我们自己的这个列表里面来
158         if not self.list_display_links:
159             new_li.append(ModelSubject.edit)  # &&& 跟如下同样特征的代码块相呼应我们在这里使用类名去调用函数名,得到的是一个函数的方法,
160         # 函数如果有参数是需要我们传参数的;但是我们如果使用self去调用的话,self就是实例化出来的对象,
161         # 而我们的对象去调用函数方法的时候就不需要去传自己了也就是self,
162         new_li.append(ModelSubject.dele)
163         new_li.insert(0, ModelSubject.checkbox)  # 把checkbox放到第一个位置,使用insert插入到索引为0
164         """
165         # @@@ 跟下面特殊标识的代码块相呼应
166         new_li.append(self.edit)
167         new_li.append(self.dele)
168         new_li.insert(0,self.checkbox)
169         """
170         return new_li
171 
172     def get_search_condition(self):
173         from django.db.models import Q
174         search_condition = Q()
175         search_condition.connector = 'or'
176         if self.search_fields:
177             key_word = self.request.GET.get('q')
178             if key_word:
179                 for search_field in self.search_fields:
180                     search_condition.children.append((search_field+"__contains", key_word))
181         return search_condition
182 
183     # 处理用户自定义的link超链接字段标签,然后让超链接携带url键值对参数方法
184     def get_link_tag(self, obj, val):
185         params = self.request.GET
186         import copy
187         params = copy.deepcopy(params)
188         params._mutable = True
189         from django.http import QueryDict
190         qqx = QueryDict(mutable=True)
191         qqx['list_filter'] = params.urlencode()
192         whh = mark_safe("<a href='{}?{}'>{}</a>".format(self.get_edit_url(obj), qqx.urlencode(), val))
193         return whh
194 
195     # 展示页面
196     def stand_li(self, request):
197         # print(self.model)
198         # 所以我们在这里可以获取到当前的url里面的表名,然后直接使用orm语句即可得到当前表格的所有信息
199         self.request = request
200 
201         # 关于search的模糊查询
202         search_condition = self.get_search_condition()
203 
204         # action
205         queryset = self.model.objects.filter(search_condition)
206         # a=self.model.objects.all().count()  # 这样就是可以获取我们的queryset集合的总数据长度,
207         # 然后就可以用它去传给我们的分页组件,用它也可以,直接用count就能获取数据长度,或者是用len也行,我之前都是用len获取的
208         sl = StandLi(self, request, queryset)  # 这里是把我们的StandLi这个类所需要的参数都传给它,然后通过StandLi实例化出来的一个对象
209         # 然后在这里实例化出来一个对象我在这里调用那个对象就能够使用那个类里面的封装的方法了
210         add_url = self.get_add_url()
211         return render(request, 'file/hello.html', locals())
212 
213     # ModelForm校验添加和编辑页面
214     def get_modelform_class(self):
215         from django.forms import widgets
216 
217         class AllModelForm(ModelForm):
218             class Meta:
219                 model = self.model
220                 fields = '__all__'
221         if not self.model_form_class:  # 这里的model_form_class在上面被定义了默认是None,
222             # 我们的分发下去的App里面自定义的file文件里面注册model类的时候实例化出来的对象,在注册的时候传过来的这个变量
223             return AllModelForm
224         else:
225             return self.model_form_class
226 
227     # ModelForm校验数据添加页面
228     def add_view(self, request):
229         FormClass = self.get_modelform_class()
230         if request.method == 'GET':
231             form = FormClass()
232             return render(request, 'file/add.html', {'form': form})
233         else:
234             data_list = FormClass(data=request.POST)
235             if data_list.is_valid():
236                 data_list.save()
237                 return redirect(self.get_stand_url())
238             else:
239                 return render(request, 'file/add.html', {'form': data_list})
240 
241     # ModelForm校验数据编辑页面
242     def edit_view(self, request, id):
243         edit_list = self.model.objects.filter(pk=id).first()
244         FormClass = self.get_modelform_class()
245         if request.method == 'GET':
246             data_list = FormClass(instance=edit_list)
247             return render(request, 'file/edit.html', {'form': data_list})
248         else:
249             data_list = FormClass(data=request.POST, instance=edit_list)
250         if data_list.is_valid():
251             data_list.save()
252             return redirect(self.get_stand_url())
253         else:
254             return render(request, 'file/edit.html', {'form': data_list})
255 
256     # 数据删除页面
257     def dele_view(self, request, id):
258         del_obj = self.model.objects.filter(pk=id).first()
259         if request.method == 'GET':
260             stand_url = self.get_stand_url()
261             return render(request, 'file/dele.html', {'del_obj': del_obj, 'list_url': stand_url})
262         else:
263             del_obj.delete()
264 
265             return redirect(self.get_stand_url())
266 
267     # 获取url,此为第二次分发
268     def get_urls(self):
269         temp = []
270         temp.append(url(r'^$', self.stand_li, name='%s_standlist' % self.namespace))
271         temp.append(url(r'^(\d+)/dele/', self.dele_view, name='%s_dele' % self.namespace))
272         temp.append(url(r'^(\d+)/edit/', self.edit_view, name='%s_edit' % self.namespace))
273         temp.append(url(r'^add/', self.add_view, name='%s_add' % self.namespace))
274         return temp
275 
276     @property
277     def urls(self):
278         return self.get_urls()
279 
280 
281 class Stark(object):
282     """
283     我们这里面的功能是可以跟上面的类写到一起去的,但是我们为了功能解耦,所以就分开写了,这里的主要功能就是
284     生成registry的字典,把键值对生成,然后我们最终的结果是要得到一个实例化对象,供我们后面的程序调用,这里的类才是主要的,核心的代码块
285     而我们上面的那个ModelSubject是辅助我们这里的功能,它之所以分发出去是为了便于扩展其他的功能,我们的自定义样式,
286     还有很多的方法和参数,就像我们的admin里面的ModelAdmin一样,长达1400多行代码,单独把它分离出去便于功能的扩展
287     """
288 
289     def __init__(self):
290         self._registry = {}  # 这里是定义一个私有属性,就是为了避免被子类修改
291 
292     # 注册model表
293     def register(self, model, model_config=None):  # 我们是仿照着admin的源码写的组件,这里的model_config默认值是None,
294         # 我们在传参的时候,如果给它传值,那么就使用我们传入的值替换掉这个None
295         # 它的源码里面有这几个参数,我们也要按照顺序把这几个参数加进来
296         if not model_config:
297             model_config = ModelSubject  # 我们这里的model_config我们上面的类ModelSubject实例化出来的对象,
298             # 它是上面的类所实例化出来的对象,这一句写得明明白白的,这大白话再看不懂就真是白学了,
299         self._registry[model] = model_config(model, self)
300 
301     # 获取url,第一次分发
302     def get_urls(self):
303         li = []
304         for model, model_config in self._registry.items():  # 我们在这里所循环的model_config就是
305             # 我们往上数第四行所实例化出来的那个model_config,它是上面的ModelSubject这个类所实例化出来对象,
306             model_name = model._meta.model_name  # 这里的._meta.model_name是获取字符串格式的类名,
307             app_label = model._meta.app_label  # 这里的._meta.app_labe获取的是字符串格式的App名,都是为了跟url做匹配,
308             sli = url(r'%s%s/' % (app_label, model_name), (model_config.urls, None, None))  # 我们这里的model_config,
309             # 它后面的.urls是在调用一个私有方法,我们的私有方法就是使用.urls来调用,不用加上括号,
310             # 因为有@property这个装饰器在里面起到的作用,然后我们需要找到model_config这个实例对象是哪个类生成的,
311             # 然后找到该类所拥有的方法,从里面找到urls,届时,那个urls就是我们在这里调用的那个urls了,
312             # 所以关键的点就是我们的model_config,老师讲课的时候一再地强调过这个model_config从何而来,这个是关键,
313             li.append(sli)
314         return li
315 
316     # 我们最终的数据结构就是这样的,嵌套多层
317     # [
318     # url(
319     # r'',(
320     # [
321     # (url(r'',views.add)),
322     # (url(r'',views.edit)),
323     # ],
324     # none,none)
325     # )
326     # ]
327     @property
328     def urls(self):
329         return self.get_urls(), None, None
330 
331 
332 site = Stark()
核心组件代码

 

前端模板:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
 6     <meta name="viewport" content="width=device-width, initial-scale=1">
 7     <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
 8     <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
 9     <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
10     <title>Title</title>
11 </head>
12 <body>
13 <div class="jumbotron">
14     <div class="container">
15         <h1>数据展示</h1>
16         <h2>code change the world</h2>
17     </div>
18 </div>
19 
20 <div class="container">
21     <div class="row">
22         <div class="col-md-8">
23             <div>
24                 <a href="{{ add_url }}">
25                     <button class="btn btn-primary" value="添加">添加</button>
26                 </a>
27             {% if sl.config.search_fields %}
28             <div class="pull-right form-group">
29 
30                 <form action="" method="get" class="form-inline">
31                     <input type="text" class="form-control" name="q" value="">
32                     <input type="submit" class="btn btn-info" value="search">
33                 </form>
34 
35             </div>
36             {% endif %}
37                 <table class="table table-stripped table-hover">
38 
39                     <thead>
40                     <tr>
41                         {% for foo in sl.get_header %}
42                             <td>{{ foo }}</td>
43                         {% endfor %}
44                     </tr>
45                     </thead>
46                     <tbody>
47                     {% for data in sl.get_body %}
48                         <tr>
49                             {% for item in data %}
50                                 <td>{{ item }}</td>
51                             {% endfor %}
52                         </tr>
53                     {% endfor %}
54 
55                     </tbody>
56 
57                 </table>
58             </div>
59             <div class="text-center">
60                 <nav aria-label="Page navigation">
61                     <ul class="pagination">
62                         {{ sl.pagination.page_html|safe }}
63                     </ul>
64                 </nav>
65             </div>
66         </div>
67     </div>
68 </div>
69 <script src="/static/js/hello.js">
70     {#    我们的js代码里面需要注意单引号和双引号的区别,不能轻易改写,还有选择器,组合选择器之间需要空格#}
71 </script>
72 </body>
73 </html>
前端模板渲染

 

分页器:

  1 # 分页封装方法(带参数版)
  2 class MyPage(object):
  3 
  4     def __init__(self, page_num, total_count, base_url, params, per_page_num=3, max_show=5):
  5         """
  6         :param params: 当前页码所携带的url里面的键值对参数
  7         :param page_num: 当前页面
  8         :param total_count: 数据总个数
  9         :param base_url: 分页页码跳转的url
 10         :param per_page_num: 每一页显示多少条数据
 11         :param max_show: 页面上最多显示多少页码
 12         """
 13         # 实例化时传进来的参数
 14         # 我们在这里捕捉一下异常,把传进去的参数改成数字类型,否则就返回第一页
 15         try:
 16             page_num = int(page_num)
 17         except Exception as e:
 18             page_num = 1
 19         if page_num < 1:  # 如果我们的当前页码出现负数的时候,这里就直接返回第一页,避免出现负数的情况
 20             page_num = 1
 21         self.params = params
 22         self.page_num = page_num
 23         self.total_count = total_count
 24         self.base_url = base_url
 25         self.per_page_num = per_page_num
 26         self.max_show = max_show
 27         self.half_show = int((self.max_show-1)/2)
 28         total_page_num, more = divmod(total_count, per_page_num)
 29         """
 30         我们使用总数据的个数对每页显示的数据个数取余,得到的商是页码数,如果有余数就在商的页码数上加一
 31         """
 32         if more:
 33             total_page_num += 1
 34         self.total_page_num = total_page_num
 35 
 36         import copy
 37         params = copy.deepcopy(params)  # 这里的QueryDict里面是有内置方法,它存储的是一个字典,
 38         # 我们的url里面的参数都在这里面,我们要用它就需要对其进行赋值操作,然后它有一个参数是_mutable默认值False,
 39         # 不能修改也不能被赋值,我们需要把params给copy一份,使用deepcopy,然后deepcopy的基础上进行赋值
 40         params._mutable = True
 41         self.params = params  # self.params: {'page':23, 'title': python, 'nid': 3}
 42         # 这里就是我们的url里面携带的键值对,都封装到params里面了
 43 
 44     # 首页
 45     @property
 46     def start(self):
 47         return (self.page_num-1)*self.per_page_num
 48 
 49     # 尾页
 50     @property
 51     def end(self):
 52         return self.page_num*self.per_page_num
 53 
 54     def page_html(self):
 55         """
 56         返回页面上可以用的一段HTML
 57         一段可用的分页页码的HTML
 58         :return:
 59         """
 60         # 如果总页码数<=最大显示页码数,那么起始页码数分别是什么
 61         if self.total_page_num <= self.max_show:
 62             page_start = 1
 63             page_end = self.total_page_num
 64         else:  # 如果当前页<=最多显示的页码数的一半,那么起始页码分别是什么
 65             """
 66             假设,我们最多显示7个分页,那么第一页就是1,最后一页就是7,但是我们的当前页是2,
 67             它往前倒推7/2商3余1,2-3得到当前页的首页-1,就是负数了,所以这个时候需要做限制,让首页等于1,
 68             """
 69             if self.page_num <= self.half_show:
 70                 page_start = 1
 71                 page_end = self.max_show
 72             else:
 73                 # 如果当前页>=总页码数-最多显示的页码数的一半,那么起始页码分别是什么
 74                 """
 75                 如果我们在第6页,我们的页面最多显示7个页码,而我们的总数据就只能显示8页的话,
 76                 倒推的6+7/2商3余1,就是(6+3)>8,我们的第9页就是空白页,这个时候就需要加以限制,
 77                 此时第一页就是8-6+1,也就是从第二页开始,一直到第八页,就刚好是7页,这样就完美了
 78                 此时最后一页就是数据最多所展示的页码第8页
 79                 """
 80                 if self.page_num >= self.total_page_num - self.half_show:
 81                     page_start = self.total_page_num - self.max_show + 1
 82                     page_end = self.total_page_num
 83                 else:  # 最后到这里我们判断了数据所在的页码出现在最前面把负数页码排除了,也判断了数据所在的页码出现最后面把空白页码排除了,
 84                     # 也判断了总页码数还不够我们所设置的最大页码显示,就剩下最后一种情况了,那就是当前页不在最后也不在最前,
 85                     # 直接用当前页加上或减去最大显示页的1/2,就得到了起始页面
 86                     page_start = self.page_num - self.half_show
 87                     page_end = self.page_num + self.half_show
 88 
 89         # 生成前页码的HTML
 90         page_html_list = []
 91 
 92         # 生成第一页
 93         self.params['page'] = 1
 94         page_first_tmp = '<li><a href="{}?{}">首页</a><li>'.format(self.base_url, self.params.urlencode())
 95         page_html_list.append(page_first_tmp)
 96 
 97         # 生成上一页
 98         if self.page_num <= 1:
 99             page_prev_tmp = '<li class=disabled><a href="#">上一页</a></li>'
100         else:
101             self.params['page'] = self.page_num-1
102             page_prev_tmp = '<li><a href="{}?{}">上一页</a></li>'.format(self.base_url, self.params.urlencode())
103 
104         page_html_list.append(page_prev_tmp)
105 
106         # 生成页码中间页数前半截
107         for i in range(page_start, page_end+1):
108             self.params['page'] = i
109             if i == self.page_num:
110                 tmp = '<li class="active"><a href="{}?{}">{}</a></li>'.format(self.base_url, self.params.urlencode(), i)
111             else:
112                 tmp = '<li><a href="{}?{}">{}</a></li>'.format(self.base_url, self.params.urlencode(), i,)
113 
114             page_html_list.append(tmp)
115 
116         # 生成页码中间页数后半截
117         if self.page_num + 1 > self.total_page_num:
118             page_next_tmp = '<li class="disabled"><a href="#">下一页</a></li>'
119         else:
120             self.params['page'] = self.page_num+1
121             page_next_tmp = '<li><a href="{}?{}">下一页</a></li>'.format(self.base_url, self.params.urlencode(),)
122 
123         page_html_list.append(page_next_tmp)
124 
125         # 生成最后一页
126         self.params['page'] = self.total_page_num
127         page_last_tmp = '<li><a href="{0}?{1}">尾页</a></li>'.format(self.base_url, self.params.urlencode(),)
128         page_html_list.append(page_last_tmp)
129 
130         return "".join(page_html_list)
分页器

 

组件的使用:

1 class BookConfig(ModelSubject):
2      list_display = ['id', 'title']
3      list_display_links = ['title']
4      search_fields = ['title', ]
5     
6 site.register(Book, BookConfig)
file.py代码

 

posted @ 2018-03-16 20:47  dream-子皿  阅读(140)  评论(0编辑  收藏  举报