Python CRM项目三

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 }}<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>
View Code

在项目中由于分页之前要进行条件筛选和排序,所以分页如下

1 from django.core.paginator import Paginator,EmptyPage, PageNotAnInteger
View Code
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
View Code
 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})
View Code
 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 %}
View Code

自定义标签的tags的方法

1.导入

1 from django import template
2 from django.utils.safestring import mark_safe
3 register = template.Library()
View Code

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
View Code

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 += '<td>%s</td>'%column_data
20     return mark_safe(row_ele)
View Code

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 ''
View Code

5.动态加载筛选条件 render_filter_ele

 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)
View Code

 当然,上述的代码会导致错误,这是必然发生的,因为我们没有和之后的过滤,排序结合起来,目前只用了分页,所以比较片面,后面还需在功能上进行优化

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
View Code

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
View Code

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 ''})
View Code

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)
View Code

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))
View Code

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)
View Code

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 %}
View Code

 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
View Code

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))
View Code

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
View Code

原先代码修改

 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
View Code

在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 ''})
View Code

前端

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>
View Code

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)
View Code
原文地址:https://www.cnblogs.com/luhuajun/p/7800776.html