您现在的位置是: 网站首页 >Django >DjangoCRM客户关系管理 Django

【CRM客户关系管理】11.为查询结果添加分页和排序功能

admin2018年12月4日 09:26 Django | Html | Python 1059人已围观

DjangoCRM客户关系管理简介 使用Django2.1.3+Bootstrap实现CRM系统,仿照Django Admin重写后台 Github地址:https://github.com/xyliurui/DjangoCRM Django版本:2.1.3

### 为查询结果添加分页 参考官方文档 https://docs.djangoproject.com/zh-hans/2.1/topics/pagination/ #### 添加分页 ```python from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator @login_required def table_detail(request, app_name, model_name): """取出指定model里的数据返回到前端""" # 拿到admin_class后,通过它获取model admin_class = site.enable_admins[app_name][model_name] # print(admin_class) # 执行djadmin.py定义的注册模型类 queryset = admin_class.model.objects.all() # print(queryset) # 进行过滤 queryset, filter_conditions = get_filter_result(request, queryset) # 将过滤字典保存到全局注册类中 admin_class.filter_conditions = filter_conditions # 查询集结果分页 paginator = Paginator(queryset, 1) # Show 10 contacts per page page = request.GET.get('page') try: queryset = paginator.get_page(page) except PageNotAnInteger: queryset = paginator.get_page(1) except EmptyPage: queryset = paginator.get_page(paginator.num_pages) return render(request, 'djadmin/table_detail.html', locals()) ``` 这时候访问 http://127.0.0.1:8000/djadmin/crm/customerinfo/ 就只会显示一个结果了 ![BLOG_20181204_093512_29](/media/blog/images/2018/12/BLOG_20181204_093512_29.png "博客图集BLOG_20181204_093512_29.png") 理论上访问 http://127.0.0.1:8000/djadmin/crm/customerinfo/?page=2 就会显示第二页,但实际报错 ![BLOG_20181204_093505_85](/media/blog/images/2018/12/BLOG_20181204_093505_85.png "博客图集BLOG_20181204_093505_85.png") #### 分页报错排除筛选条件 因为后台在处理`page=2`时将这个值当作`get_filter_result(request, queryset)`的过滤条件了,需要排除键是`page`的结果 ```python def get_filter_result(request, queryset): """获取过滤的字段,并返回过滤后的查询集和过滤的字典""" filter_conditions = {} # 获取过滤的字段 for k, v in request.GET.items(): # 分页将不计入筛选值 if k == 'page': continue if v: # 所选的值不会空是保存到字典中 filter_conditions[k] = v return queryset.filter(**filter_conditions), filter_conditions ``` 现在访问第二页 http://127.0.0.1:8000/djadmin/crm/customerinfo/?page=2 就可以得到正常的结果 ![BLOG_20181204_093441_99](/media/blog/images/2018/12/BLOG_20181204_093441_99.png "博客图集BLOG_20181204_093441_99.png") #### 分页按钮功能 使用Django自带的分页,将以下代码添加到table_detail.html模板最下方 ```html <div class="pagination"> <span class="step-links"> {% if queryset.has_previous %} <a href="?page=1">&laquo; first</a> <a href="?page={{ queryset.previous_page_number }}">previous</a> {% endif %} <span class="current"> Page {{ queryset.number }} of {{ queryset.paginator.num_pages }}. </span> {% if queryset.has_next %} <a href="?page={{ queryset.next_page_number }}">next</a> <a href="?page={{ queryset.paginator.num_pages }}">last &raquo;</a> {% endif %} </span> </div> ``` ![BLOG_20181204_093433_42](/media/blog/images/2018/12/BLOG_20181204_093433_42.png "博客图集BLOG_20181204_093433_42.png") #### 使用bootstrap分页按钮 在项目templates目录下,创建includes文件夹,然后创建pagination.html文件 ```html <ul class="pagination pagination-sm m-0 float-right"> {% if page.number > 1 %} <li class="page-item"><a class="page-link" href="?page=1" aria-label="">首页</a></li> {% endif %} {% if page.has_previous %} <li class="page-item"><a class="page-link" href="?page={{ page.previous_page_number }}">&laquo;</a></li> {% endif %} {% for pg in page.paginator.page_range %} {% if page.number == pg %} <li class="page-item active"><a class="page-link" href="?page={{ pg }}">{{ pg }}</a></li> {% elif pg > page.number|add:'-3' and pg < page.number|add:'3' %} <li class="page-item"><a class="page-link" href="?page={{ pg }}">{{ pg }}</a></li> {% endif %} {% endfor %} {% if page.has_next %} <li class="page-item"><a class="page-link" href="?page={{ page.next_page_number }}">&raquo;</a></li> {% endif %} {% if page.number != page.paginator.num_pages %} <li class="page-item"><a class="page-link" href="?page={{ page.paginator.num_pages }}" aria-label="">尾页</a></li> {% endif %} </ul> ``` 在详情中包含分页模块,下方为自带的分页,上部为bootstrap分页模块 ```html <div> {% include 'includes/pagination.html' with page=queryset %} </div> <div class="pagination"> <span class="step-links"> {% if queryset.has_previous %} <a href="?page=1">&laquo; first</a> <a href="?page={{ queryset.previous_page_number }}">previous</a> {% endif %} <span class="current"> Page {{ queryset.number }} of {{ queryset.paginator.num_pages }}. </span> {% if queryset.has_next %} <a href="?page={{ queryset.next_page_number }}">next</a> <a href="?page={{ queryset.paginator.num_pages }}">last &raquo;</a> {% endif %} </span> </div> ``` ![BLOG_20181204_093403_99](/media/blog/images/2018/12/BLOG_20181204_093403_99.png "博客图集BLOG_20181204_093403_99.png") 测完完成后就可以在视图中把每页数量设置为10条了。 ### 排序功能 #### 处理排序的函数 在djadmin应用下的视图中,增加处理排序功能的函数`get_order_result(request, queryset, admin_class)` ```python def get_order_result(request, queryset, admin_class): """获取request中的排序字段,然后返回排序后的结果""" current_order_field = dict() # 通过获取前端传过来的排序的索引字符串 order_value = request.GET.get('_order') # _order的值为list_display列表的索引:-0, 0, 1, -3等 if order_value: # 通过索引找到要排序的字段,因为索引可能是正数或负数,所以要用绝对值 order_field = admin_class.list_display[abs(int(order_value))] # 记录当前的排序字段,以list_display列表的值为键,request的值为值保存到字典中 current_order_field[order_field] = order_value # 判断是正序或者是倒序,如果是倒序,需要添加负号 if order_value.startswith('-'): order_field = '-' + order_field return queryset.order_by(order_field), current_order_field else: return queryset, current_order_field ``` #### 详情视图调用排序函数 修改详情视图`table_detail(request, app_name, model_name)`,在过滤和分页的中间增加排序调用 ```python @login_required def table_detail(request, app_name, model_name): """取出指定model里的数据返回到前端""" # 拿到admin_class后,通过它获取model admin_class = site.enable_admins[app_name][model_name] # print(admin_class) # 执行djadmin.py定义的注册模型类 queryset = admin_class.model.objects.all() # print(queryset) # 进行过滤 queryset, filter_conditions = get_filter_result(request, queryset) # 将过滤字典保存到全局注册类中 admin_class.filter_conditions = filter_conditions # 排序,返回排序的结果和排序的字段字典 queryset, current_order_field = get_order_result(request,queryset, admin_class) # 查询集结果分页 paginator = Paginator(queryset, 10) # Show 10 contacts per page page = request.GET.get('page') try: queryset = paginator.get_page(page) except PageNotAnInteger: queryset = paginator.get_page(1) except EmptyPage: queryset = paginator.get_page(paginator.num_pages) return render(request, 'djadmin/table_detail.html', locals()) ``` #### 排序报错排除筛选条件 修改djadmin应用视图的函数`get_filter_result(request, queryset)`,排除排序字段,这儿就以如果键以`_`开头,则不进行筛选。 ```python def get_filter_result(request, queryset): """获取过滤的字段,并返回过滤后的查询集和过滤的字典""" filter_conditions = {} # 获取过滤的字段 for k, v in request.GET.items(): # 分页将不计入筛选值 if k == 'page' or k.startswith('_'): continue if v: # 所选的值不会空是保存到字典中 filter_conditions[k] = v return queryset.filter(**filter_conditions), filter_conditions ``` 这时候如果访问 http://127.0.0.1:8000/djadmin/crm/customerinfo/?_order=5 就会按客户状态进行排序 ![BLOG_20181204_093347_88](/media/blog/images/2018/12/BLOG_20181204_093347_88.png "博客图集BLOG_20181204_093347_88.png") 访问 http://127.0.0.1:8000/djadmin/crm/customerinfo/?_order=-5 按客户状态倒序 ![BLOG_20181204_093326_49](/media/blog/images/2018/12/BLOG_20181204_093326_49.png "博客图集BLOG_20181204_093326_49.png") #### 设计排序点击链接 观察模板标签中的`build_table_head_name(admin_class)`函数,假如我们要实现点击表格头部进行排序,实现起来不太方便 ```python # 显示模型表的中文名称 @register.simple_tag def build_table_head_name(admin_class): th = '' if admin_class.list_display: for display_field in admin_class.list_display: # 获取列中的字段对象 display_field_obj = admin_class.model._meta.get_field(display_field) # print(display_field_obj.verbose_name) tmp = "<th>{}</th>".format(display_field_obj.verbose_name) th += tmp else: th += "<th>{}</th>".format(admin_class.model._meta.verbose_name) # 如果没有自定义注册,则表格标题就显示模型的别名verbose_name return mark_safe(th) ``` 所以修改表格的头部,暂时在模板中处理显示表头的功能 ```html <thead> <tr> {% if admin_class.list_display %} {% for display_field in admin_class.list_display %} <th><a href="?_order={% get_sorted_data display_field current_order_field forloop.counter0 %}">{{ display_field }} <span class="glyphicon glyphicon-triangle-bottom" aria-hidden="true"></span></a> </th> {% endfor %} {% else %} {% build_table_head_name admin_class %} {% endif %} <!-- {% build_table_head_name admin_class %} --> </tr> </thead> ``` 字体图标: https://v3.bootcss.com/components/ 排序样式如下 ![BLOG_20181204_093316_70](/media/blog/images/2018/12/BLOG_20181204_093316_70.png "博客图集BLOG_20181204_093316_70.png") 下面来处理这些箭头的链接功能:实现只显示当前排序字段的箭头,以及根据正倒序显示不同的箭头方向。 #### 处理箭头链接功能 在djadmin应用的模板标签templatetags\djadmin_tags.py中,新建`get_sorted_data(display_field, current_order_field, forloop_counter)`函数,用于返回排序的链接和图标样式. `current_order_field`为当前排序的字典,字典键为`list_display`的值,字典值为`list_display`的索引正负值,用于判定正倒序 ```python @register.simple_tag def get_sorted_data(display_field, current_order_field, forloop_counter): print(current_order_field) # {'status': '-5'}假如是按客户状态(列表索引为5) print(display_field) # 遍历显示list_display列表值 if display_field in current_order_field.keys(): # 得到当前排序的字段 if current_order_field[display_field].startswith('-'): order_data = current_order_field[display_field].replace('-', '') # 去掉倒序 else: order_data = '-' + current_order_field[display_field] return order_data return forloop_counter # 如果不是当前排序,直接默认正序,也就是list_display的索引值 ``` 现在点击表头的字段都可以按照该字段进行排序了 ![BLOG_20181204_093252_40](/media/blog/images/2018/12/BLOG_20181204_093252_40.png "博客图集BLOG_20181204_093252_40.png") #### 排序页面显示优化 `<span class="glyphicon glyphicon-triangle-bottom" aria-hidden="true"></span>` 如何实现上下箭头切换以及可以不显示箭头 在模板标签中再增加一个函数,这个函数逻辑上和`get_sorted_data`函数差不多 ```python @register.simple_tag def get_sorted_arrow(display_field, current_order_field, forloop_counter): if display_field in current_order_field.keys(): if current_order_field[display_field].startswith('-'): arrow_direction = 'bottom' else: arrow_direction = 'top' span = '<span class="glyphicon glyphicon-triangle-{}" aria-hidden="true"></span>'.format(arrow_direction) return mark_safe(span) return '' ``` 然后修改table_detail.html模板表头元素 ```html <thead> <tr> {% if admin_class.list_display %} {% for display_field in admin_class.list_display %} <th> <a href="?_order={% get_sorted_data display_field current_order_field forloop.counter0 %}"> {{ display_field }} {% get_sorted_arrow display_field current_order_field forloop.counter0 %} </a> </th> {% endfor %} {% else %} {% build_table_head_name admin_class %} {% endif %} <!-- {% build_table_head_name admin_class %} --> </tr> </thead> ``` ![BLOG_20181204_093239_15](/media/blog/images/2018/12/BLOG_20181204_093239_15.png "博客图集BLOG_20181204_093239_15.png") ![BLOG_20181204_093225_79](/media/blog/images/2018/12/BLOG_20181204_093225_79.png "博客图集BLOG_20181204_093225_79.png")

很赞哦! (0)

文章交流

  • emoji
0人参与,0条评论

当前用户

未登录,点击   登录

站点信息

  • 建站时间:网站已运行2076天
  • 系统信息:Linux
  • 后台程序:Python: 3.8.10
  • 网站框架:Django: 3.2.6
  • 文章统计:256 篇
  • 文章评论:60 条
  • 腾讯分析网站概况-腾讯分析
  • 百度统计网站概况-百度统计
  • 公众号:微信扫描二维码,关注我们
  • QQ群:QQ加群,下载网站的学习源码
返回
顶部
标题 换行 登录
网站