1.分頁:html
分頁使用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 }}<br /> 23 ... 24 {% endfor %} 25 #分頁組件 26 <div class="pagination"> 27 <span class="step-links"> 28 {% if contacts.has_previous %} 29 <a href="?page={{ contacts.previous_page_number }}">previous</a> 30 {% endif %} 31 32 <span class="current"> 33 Page {{ contacts.number }} of {{ contacts.paginator.num_pages }}. 34 </span> 35 36 {% if contacts.has_next %} 37 <a href="?page={{ contacts.next_page_number }}">next</a> 38 {% endif %} 39 </span> 40 </div>
在項目中因爲分頁以前要進行條件篩選和排序,因此分頁以下django
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 %} 2 <div class="panel panel-info"> 3 <div class="panel-heading"> 4 <h3 class="panel-title">Panel title</h3> 5 </div> 6 <div class="panel-body"> 7 <div class="row"> 8 {# <!--將篩選提交提交到後臺進行查詢--!>#} 9 <form method="get"> 10 {% for condition in admin_class.list_filters %} 11 <div class="col-lg-2"> 12 <span>{{ condition }}</span> 13 #後臺經過條件,數據類,所選條件進行提取結果集 14 {% render_filter_ele condition admin_class filter_conditions %} 15 </div> 16 {% endfor %} 17 <div class="col-lg-2"> 18 <input type="submit" class="btn btn-info" style="margin-top:20px"> 19 </div> 20 </form> 21 </div> 22 {# <!--動態展現後端的表格--!>#} 23 <table class="table table-hover"> 24 <thead> 25 <tr> 26 {% for column in admin_class.list_display %} 27 <th>{{ column }}</th> 28 {% endfor %} 29 </tr> 30 </thead> 31 <tbody> 32 {# <!--動態展現後端的表格中的數據--!>#} 33 {% for obj in query_sets %} 34 <tr> 35 {% bulid_table_row obj admin_class %} 36 </tr> 37 {% endfor %} 38 </tbody> 39 </table> 40 {# <!--分頁--!>#} 41 <nav aria-label="..."> 42 <ul class="pagination"> 43 {% if query_sets.has_previous %} 44 <li><a href="?page={{ query_sets.previous_page_number }}">上一頁</a></li> 45 {% endif %} 46 {% for loop_counter in query_sets.paginator.page_range %} 47 {% render_page_ele loop_counter query_sets %} 48 {% endfor %} 49 {% if query_sets.has_next %} 50 <li><a href="?page={{ query_sets.next_page_number }}">下一頁</a></li> 51 {% endif %} 52 </ul> 53 </nav> 54 </div> 55 </div> 56 {% endblock %}
自定義標籤的tags的方法後端
1.導入app
1 from django import template 2 from django.utils.safestring import mark_safe 3 register = template.Library()
2.動態加載表格 render_app_nameide
1 @register.simple_tag 2 def render_app_name(admin_class): 3 '''渲染動態獲取表名''' 4 return admin_class.model._meta.verbose_name_plural
3.動態展現表格中的數據 build_table_rowoop
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 += '<td>%s</td>'%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= '<li class="%s"><a href="?page=%s">%s</a></li>'%(ele_class,loop_counter,loop_counter) 10 return mark_safe(ele) 11 return ''
5.動態加載篩選條件 render_filter_eleui
1 @register.simple_tag 2 def render_filter_ele(condition,admin_class,filter_conditions): 3 select_ele = '<select class="form-control" name="%s"><option value="">----</option>'%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 += '<option value="%s" %s>%s</option>'%(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 += '<option value="%s" %s>%s</option>' % (choice_item[0], selected,choice_item[1]) 20 selected = '' 21 select_ele+='</select>' 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 = '<select class="form-control" name="%s"><option value="">----</option>'%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 += '<option value="%s" %s>%s</option>'%(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 += '<option value="%s" %s>%s</option>' % (choice_item[0], selected,choice_item[1]) 21 selected = '' 22 select_ele+='</select>' 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 = '<th><a href="?{filters}&o={orderby_key}">{column}</a>{sort_icon}</th>' 8 if orderby_key: 9 if orderby_key.startswith('-'): 10 sort_icon = '<span class="glyphicon glyphicon-chevron-up"></span>' 11 else: 12 sort_icon = '<span class="glyphicon glyphicon-chevron-down"></span>' 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 += '<li class="%s"><a href="?page=%s%s&o=%s">%s</a></li>' % (ele_class, page_num, filters,previous_orderby, page_num) 19 else: 20 if not added_dot_ele:#如今尚未加... 21 page_btns += '<li><a>...</a></li>' 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 %} 5 <div class="panel panel-info"> 6 <div class="panel-heading"> 7 <h3 class="panel-title">Panel title</h3> 8 </div> 9 <div class="panel-body"> 10 <div class="row"> 11 {# <!--將篩選提交提交到後臺進行查詢--!>#} 12 <form method="get"> 13 {% for condition in admin_class.list_filters %} 14 <div class="col-lg-2"> 15 <span>{{ condition }}</span> 16 {# 後臺經過條件,數據類,所選條件進行提取結果集#} 17 {% render_filter_ele condition admin_class filter_conditions %} 18 </div> 19 {% endfor %} 20 <div class="col-lg-2"> 21 <input type="submit" class="btn btn-info" style="margin-top:20px"> 22 </div> 23 </form> 24 </div> 25 {# <!--動態展現後端的表格--!>#} 26 <table class="table table-hover"> 27 <thead> 28 <tr> 29 {% for column in admin_class.list_display %} 30 {# 動態展現表格中的數據,排序關鍵字,和篩選條件#} 31 {% build_table_header_column column orderby_key filter_conditions %} 32 {% endfor %} 33 </tr> 34 </thead> 35 <tbody> 36 {# <!--動態展現後端的表格中的數據--!>#} 37 {% for obj in query_sets %} 38 <tr> 39 {% bulid_table_row obj admin_class %} 40 </tr> 41 {% endfor %} 42 </tbody> 43 </table> 44 <p>總計:{{ query_sets.paginator.count }}條</p> 45 {# <!--分頁--!>#} 46 <nav aria-label="..."> 47 <ul class="pagination"> 48 {% if query_sets.has_previous %} 49 <li><a href="?page={{ query_sets.previous_page_number }}">上一頁</a></li> 50 {% endif %} 51 {% build_paginations query_sets filter_conditions previous_orderby %} 52 {% if query_sets.has_next %} 53 <li><a href="?page={{ query_sets.next_page_number }}">下一頁</a></li> 54 {% endif %} 55 </ul> 56 </nav> 57 </div> 58 59 </div> 60 {% endblock %}
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 = '<th><a href="?{filters}&o={orderby_key}">{column}</a>{sort_icon}</th>' 8 if orderby_key: 9 if orderby_key.startswith('-'): 10 sort_icon = '<span class="glyphicon glyphicon-chevron-up"></span>' 11 else: 12 sort_icon = '<span class="glyphicon glyphicon-chevron-down"></span>' 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 ''})
前端
1 <div class="row"> 2 <div class="col-lg-2"> 3 <input type="search" name="_q" style="margin-left:15px" class="form-control" value="{{ search_text }}"> 4 </div> 5 <div class="col-lg-2"> 6 <button type="submit" class="btn btn-info">搜索</button> 7 </div> 8 </div>
13 時間檢索
1 @register.simple_tag 2 def render_filter_ele(condition,admin_class,filter_conditions): 3 select_ele = '<select class="form-control" name="{condition}"><option value="">----</option>' 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 += '<option value="%s" %s>%s</option>'%(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 += '<option value="%s" %s>%s</option>' % (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 += '<option value="%s" %s>%s</option>'%(date[1],selected,date[0]) 37 filter_field_name = '%s__gte'%condition 38 else: 39 filter_field_name = condition 40 41 select_ele+='</select>' 42 select_ele=select_ele.format(condition=filter_field_name) 43 return mark_safe(select_ele)