1.分页:
分页使用Django内置的分页模块来实现
官方的分页案例
1 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger 2 from django.shortcuts import render 3 #后端 4 def listing(request): 5 contact_list = Contacts.objects.all() 6 paginator = Paginator(contact_list, 25) # Show 25 contacts per page 7 8 page = request.GET.get('page') 9 try: 10 contacts = paginator.page(page) 11 except PageNotAnInteger: 12 # If page is not an integer, deliver first page. 13 contacts = paginator.page(1) 14 except EmptyPage: 15 # If page is out of range (e.g. 9999), deliver last page of results. 16 contacts = paginator.page(paginator.num_pages) 17 18 return render(request, 'list.html', {'contacts': contacts}) 19 #前端 20 % for contact in contacts %} 21 {# Each "contact" is a Contact model object. #} 22 {{ contact.full_name|upper }}
23 ... 24 {% endfor %} 25 #分页组件 26class="pagination"> 27 class="step-links"> 28 {% if contacts.has_previous %} 29 "?page={{ contacts.previous_page_number }}">previous 30 {% endif %} 31 32 class="current"> 33 Page {{ contacts.number }} of {{ contacts.paginator.num_pages }}. 34 35 36 {% if contacts.has_next %} 37 "?page={{ contacts.next_page_number }}">next 38 {% endif %} 39 40
在项目中由于分页之前要进行条件筛选和排序,所以分页如下
1 from django.core.paginator import Paginator,EmptyPage, PageNotAnInteger
def table_filter(request,admin_class): '''进行条件过滤,并返回过滤后的数据和条件''' filter_condition = {} for k,v in request.GET.items(): if v: filter_condition[k]=v return admin_class.model.objects.filter(**filter_condition),filter_condition
1 def display_table_objs(request,app_name,table_name): 2 admin_class = king_admin.enabled_admins[app_name][table_name] 3 #有后端查询出结果集和条件,并对其进行分页操作 4 object_list,filter_conditions = table_filter(request,admin_class) 5 6 paginator = Paginator(object_list, admin_class.list_per_page) 7 page = request.GET.get('page') 8 try: 9 objects = paginator.page(page) 10 except PageNotAnInteger: 11 objects = paginator.page(1) 12 except EmptyPage: 13 objects = paginator.page(paginator.num_pages) 14 15 return render(request,'king_admin/table_objs.html',{'admin_class':admin_class, 16 'query_sets':objects, 17 'filter_conditions':filter_conditions})
1 {% block container %} 2class="panel panel-info"> 356 {% endblock %}class="panel-heading"> 46class="panel-title">Panel title
5class="panel-body"> 755class="row"> 8 {# #} 9 2122 {# #} 23class="table table-hover"> 24 25
40 {# #} 41 5426 {% for column in admin_class.list_display %} 27 30 31 32 {# #} 33 {% for obj in query_sets %} 34{{ column }} 28 {% endfor %} 2935 {% bulid_table_row obj admin_class %} 36 37 {% endfor %} 38 39
自定义标签的tags的方法
1.导入
1 from django import template 2 from django.utils.safestring import mark_safe 3 register = template.Library()
2.动态加载表格 render_app_name
1 @register.simple_tag 2 def render_app_name(admin_class): 3 '''渲染动态获取表名''' 4 return admin_class.model._meta.verbose_name_plural
3.动态展示表格中的数据 build_table_row
1 @register.simple_tag 2 def bulid_table_row(obj,admin_class): 3 '''生成数据内容的td,填充到table中,展示前端''' 4 row_ele = '' 5 for column in admin_class.list_display: 6 #获取每个字段的类型的对象 7 field_obj = obj._meta.get_field(column) 8 #判断是否是choice字段 9 if field_obj.choices: 10 #如果是choice字段,则按照choice的值进行展示 11 column_data = getattr(obj,"get_%s_display"%column)() 12 else: 13 #否则通过反射去对象中取值 14 column_data = getattr(obj,column) 15 16 if type(column_data).__name__ == 'datetime': 17 #如果是时间类型,则需要进行格式化显示 18 column_data = column_data.strftime('%Y-%m-%d %H:%M:%S') 19 row_ele += '%s '%column_data 20 return mark_safe(row_ele)
4.动态进行分页参数的切割 render_page_ele
1 @register.simple_tag 2 def render_page_ele(loop_counter,query_sets): 3 #如果当前页数-循环的次数小于1,就展示前面两页和后面两页 4 #例如当前是第五页则展示3,4,5,6,7页 5 if abs(query_sets.number-loop_counter)<=1: 6 ele_class = '' 7 if query_sets.number==loop_counter: 8 ele_class = 'active' 9 ele= '%s '%(ele_class,loop_counter,loop_counter) 10 return mark_safe(ele) 11 return ''
5.动态加载筛选条件 render_filter_ele
1 @register.simple_tag 2 def render_filter_ele(condition,admin_class,filter_conditions): 3 select_ele = ''%condition 4 field_obj = admin_class.model._meta.get_field(condition) 5 selected = '' 6 if field_obj.choices: 7 8 #choice字段的值的获取 9 for choice_item in field_obj.choices: 10 if filter_conditions.get(condition) == str(choice_item[0]): 11 selected = 'selected' 12 select_ele += ''%(choice_item[0],selected,choice_item[1]) 13 selected = '' 14 if type(field_obj).__name__=='ForeignKey': 15 #外键字段的获取 16 for choice_item in field_obj.get_choices()[1:]: 17 if filter_conditions.get(condition) == str(choice_item[0]): 18 selected = 'selected' 19 select_ele += '' % (choice_item[0], selected,choice_item[1]) 20 selected = '' 21 select_ele+='' 22 return mark_safe(select_ele)
当然,上述的代码会导致错误,这是必然发生的,因为我们没有和之后的过滤,排序结合起来,目前只用了分页,所以比较片面,后面还需在功能上进行优化
6.条件过滤
思路:前端传入过滤条件,后端组合成字典,同时过滤掉分页关键字和排序关键字,再将条件封装成字典,按条件查询即可
1 def table_filter(request,admin_class): 2 '''进行条件过滤,并返回过滤后的数据''' 3 filter_condition = {} 4 for k,v in request.GET.items(): 5 #page为分页的字段,o为排序关键字,不是数据库的查询字段,此处要进行过滤 6 if k == 'page' or k == 'o': 7 continue 8 if v: 9 filter_condition[k]=v 10 11 return admin_class.model.objects.filter(**filter_condition),filter_condition
7.单条件排序
思路:将前端传入的排序字段,后台拿到排序的关键字进行排序,排序分为正向排序和逆向排序
1 def table_sort(request,objs): 2 #获取前端的分页关键字进行排序 3 orderby_key = request.GET.get('o') 4 if orderby_key: 5 res = objs.order_by(orderby_key) 6 #如果上一次是降序,此时改成升序 7 if orderby_key.startswith('-'): 8 orderby_key = orderby_key.strip('-') 9 else: 10 #否则改成降序 11 orderby_key = '-%s'%orderby_key 12 else: 13 res = objs 14 return res,orderby_key
8.views修改,分页中集成筛选和排序
1 def display_table_objs(request,app_name,table_name): 2 admin_class = king_admin.enabled_admins[app_name][table_name] 3 #有后端查询出结果集,并对其进行分页操作 4 object_list,filter_conditions = table_filter(request,admin_class) 5 #先过滤,在排序 6 object_list,orderby_key = table_sort(request,object_list) 7 8 paginator = Paginator(object_list, admin_class.list_per_page) 9 page = request.GET.get('page') 10 try: 11 objects = paginator.page(page) 12 except PageNotAnInteger: 13 objects = paginator.page(1) 14 except EmptyPage: 15 objects = paginator.page(paginator.num_pages) 16 #传递给前端的参数有model的admin_class,分页的结果集,过滤条件,排序字段,以及上一次的排序字段 17 return render(request,'king_admin/table_objs.html',{'admin_class':admin_class, 18 'query_sets':objects, 19 'filter_conditions':filter_conditions, 20 'orderby_key':orderby_key, 21 'previous_orderby':request.GET.get('o') or ''})
9.tags自定义标签渲染
9.1 筛选条件
1 @register.simple_tag 2 def render_filter_ele(condition,admin_class,filter_conditions): 3 #渲染过滤筛选的条件,返回给前端渲染 4 select_ele = ''%condition 5 field_obj = admin_class.model._meta.get_field(condition) 6 selected = '' 7 if field_obj.choices: 8 9 #choice字段的值的获取 10 for choice_item in field_obj.choices: 11 if filter_conditions.get(condition) == str(choice_item[0]): 12 selected = 'selected' 13 select_ele += ''%(choice_item[0],selected,choice_item[1]) 14 selected = '' 15 if type(field_obj).__name__=='ForeignKey': 16 #外键字段的获取 17 for choice_item in field_obj.get_choices()[1:]: 18 if filter_conditions.get(condition) == str(choice_item[0]): 19 selected = 'selected' 20 select_ele += '' % (choice_item[0], selected,choice_item[1]) 21 selected = '' 22 select_ele+='' 23 return mark_safe(select_ele)
9.2 排序关键字
1 @register.simple_tag 2 def build_table_header_column(column,orderby_key,filter_condition): 3 #排序时要携带过滤条件 4 filters = '' 5 for k,v in filter_condition.items(): 6 filters += '&%s=%s'%(k,v) 7 ele = '{column}{sort_icon} ' 8 if orderby_key: 9 if orderby_key.startswith('-'): 10 sort_icon = '' 11 else: 12 sort_icon = '' 13 14 if orderby_key.strip('-') == column: #排序的就是当前字段 15 orderby_key = orderby_key 16 17 else: 18 orderby_key = column 19 sort_icon = '' 20 21 else:#没有排序,就默认按照当前列显示 22 orderby_key = column 23 sort_icon = '' 24 return mark_safe(ele.format(orderby_key=orderby_key,column=column,sort_icon=sort_icon,filters=filters))
9.3 分页bug修复
1 @register.simple_tag 2 def build_paginations(query_sets,filter_conditions,previous_orderby): 3 '''返回整个的分页元素''' 4 filters = '' 5 for k, v in filter_conditions.items(): 6 filters += '&%s=%s' % (k, v) 7 8 page_btns = '' 9 added_dot_ele = False 10 for page_num in query_sets.paginator.page_range: 11 #代表最前2页,或最后2页 12 if page_num < 3 or page_num > query_sets.paginator.num_pages-2 or \ 13 abs(query_sets.number - page_num) <= 1: 14 ele_class = '' 15 if query_sets.number == page_num: 16 ele_class = 'active' 17 added_dot_ele = False 18 page_btns += '%s ' % (ele_class, page_num, filters,previous_orderby, page_num) 19 else: 20 if not added_dot_ele:#现在还没有加... 21 page_btns += '... ' 22 added_dot_ele = True 23 24 return mark_safe(page_btns)
10 前端页面修改
1 {% extends 'king_admin/table_index.html' %} 2 {% load tags %} 3 4 {% block container %} 5class="panel panel-info"> 660 {% endblock %}class="panel-heading"> 79class="panel-title">Panel title
8class="panel-body"> 1058 59class="row"> 11 {# #} 12 2425 {# #} 26class="table table-hover"> 27 28
4429 {% for column in admin_class.list_display %} 30 {# 动态展示表格中的数据,排序关键字,和筛选条件#} 31 {% build_table_header_column column orderby_key filter_conditions %} 32 {% endfor %} 33 34 35 36 {# #} 37 {% for obj in query_sets %} 3839 {% bulid_table_row obj admin_class %} 40 41 {% endfor %} 42 43总计:{{ query_sets.paginator.count }}条
45 {# #} 46 57
11 排序
后台处理
1 def table_sort(request,objs): 2 #获取前端的分页关键字进行排序 3 orderby_key = request.GET.get('o') 4 if orderby_key: 5 res = objs.order_by(orderby_key) 6 if orderby_key.startswith('-'): 7 orderby_key = orderby_key.strip('-') 8 else: 9 orderby_key = '-%s'%orderby_key 10 else: 11 res = objs 12 return res,orderby_key
tags动态生成标签和触发正序和倒序
1 @register.simple_tag 2 def build_table_header_column(column,orderby_key,filter_condition): 3 filters = '' 4 for k,v in filter_condition.items(): 5 filters += '&%s=%s'%(k,v) 6 #生成每一列表头的超链接,点击触发排序 7 ele = '{column}{sort_icon} ' 8 if orderby_key: 9 if orderby_key.startswith('-'): 10 sort_icon = '' 11 else: 12 sort_icon = '' 13 14 if orderby_key.strip('-') == column: #排序的就是当前字段 15 orderby_key = orderby_key 16 17 else: 18 orderby_key = column 19 sort_icon = '' 20 21 else:#没有排序, 22 orderby_key = column 23 sort_icon = '' 24 return mark_safe(ele.format(orderby_key=orderby_key,column=column,sort_icon=sort_icon,filters=filters))
12 查找
后台处理
1 def table_search(request,admin_class,object_list): 2 search_key = request.GET.get('_q','') 3 con = Q() 4 con.connector = 'OR' 5 for search_field in admin_class.search_fields: 6 con.children.append(('%s__contains'%search_field,search_key)) 7 res = object_list.filter(con) 8 return res
原先代码修改
1 def table_filter(request,admin_class): 2 '''进行条件过滤,并返回过滤后的数据''' 3 filter_condition = {} 4 # page为分页的字段,o为排序关键字,_q是搜索关键字,不是数据库的查询字段,此处要进行过滤 5 keywords = ['page','o','_q'] 6 for k,v in request.GET.items(): 7 8 if k in keywords: 9 continue 10 if v: 11 filter_condition[k]=v 12 13 return admin_class.model.objects.filter(**filter_condition),filter_condition
在views中导入utils的查找方法
1 def display_table_objs(request,app_name,table_name): 2 admin_class = king_admin.enabled_admins[app_name][table_name] 3 #有后端查询出结果集,并对其进行分页操作 4 object_list,filter_conditions = table_filter(request,admin_class) 5 #搜索 6 object_list = table_search(request,admin_class,object_list) 7 #先过滤,在排序 8 object_list,orderby_key = table_sort(request,object_list) 9 10 paginator = Paginator(object_list, admin_class.list_per_page) 11 page = request.GET.get('page') 12 try: 13 objects = paginator.page(page) 14 except PageNotAnInteger: 15 objects = paginator.page(1) 16 except EmptyPage: 17 objects = paginator.page(paginator.num_pages) 18 19 return render(request,'king_admin/table_objs.html',{'admin_class':admin_class, 20 'query_sets':objects, 21 'filter_conditions':filter_conditions, 22 'orderby_key':orderby_key, 23 'previous_orderby':request.GET.get('o') or '', 24 'search_text':request.GET.get('_q') or ''})
前端
1class="row"> 2class="col-lg-2"> 3 "search" name="_q" style="margin-left:15px" class="form-control" value="{{ search_text }}"> 45class="col-lg-2"> 6 78
13 时间检索
1 @register.simple_tag 2 def render_filter_ele(condition,admin_class,filter_conditions): 3 select_ele = '' 4 field_obj = admin_class.model._meta.get_field(condition) 5 selected = '' 6 if field_obj.choices: 7 8 #choice字段的值的获取 9 for choice_item in field_obj.choices: 10 if filter_conditions.get(condition) == str(choice_item[0]): 11 selected = 'selected' 12 select_ele += ''%(choice_item[0],selected,choice_item[1]) 13 selected = '' 14 if type(field_obj).__name__=='ForeignKey': 15 #外键字段的获取 16 for choice_item in field_obj.get_choices()[1:]: 17 if filter_conditions.get(condition) == str(choice_item[0]): 18 selected = 'selected' 19 select_ele += '' % (choice_item[0], selected,choice_item[1]) 20 selected = '' 21 if type(field_obj).__name__ in ['DateTimeField','DateField']: 22 #日期字段获取,通过计算当前时间-天数来实现日期过滤 23 date_els = [] 24 today_ele = datetime.now().date() 25 date_els.append(['今天',today_ele]) 26 date_els.append(['昨天',today_ele - timedelta(days=1)]) 27 date_els.append(['近7天', today_ele - timedelta(days=7)]) 28 date_els.append(['本月', today_ele.replace(day=1)]) 29 date_els.append(['近30天', today_ele - timedelta(days=30)]) 30 date_els.append(['近90天', today_ele - timedelta(days=90)]) 31 date_els.append(['近180天', today_ele - timedelta(days=180)]) 32 date_els.append(['本年', today_ele.replace(month=1,day=1)]) 33 date_els.append(['近一年', today_ele - timedelta(days=365)]) 34 selected = '' 35 for date in date_els: 36 select_ele += ''%(date[1],selected,date[0]) 37 filter_field_name = '%s__gte'%condition 38 else: 39 filter_field_name = condition 40 41 select_ele+='' 42 select_ele=select_ele.format(condition=filter_field_name) 43 return mark_safe(select_ele)