您现在的位置是: 网站首页 >Django >DjangoCRM客户关系管理 Django
【CRM客户关系管理】11.为查询结果添加分页和排序功能
admin2018年12月4日 09:26 【Django | Html | Python 】 1470人已围观
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">« 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 »</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 }}">«</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 }}">»</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">« 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 »</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
当前用户
未登录,点击 登录专题目录
- 【CRM客户关系管理】01.项目介绍分析
- 【CRM客户关系管理】02.设置项目需要的模型
- 【CRM客户关系管理】03.使用Bootstrap前端模板
- 【CRM客户关系管理】04.用户登录登录及访问控制
- 【CRM客户关系管理】05.动态菜单生成,绝对URL和动态URL
- 【CRM客户关系管理】06.创建djadmin APP,并进行相关配置
- 【CRM客户关系管理】07.自动发现APP注册并显示列表
- 【CRM客户关系管理】08.取出app中model的值,根据list_display配置生成数据列表
- 【CRM客户关系管理】09.根据模型中字段的choices以及时间区间来过滤数据
- 【CRM客户关系管理】10.处理无list_display和list_filter属性时的异常情况
- 【CRM客户关系管理】11.为查询结果添加分页和排序功能
- 【CRM客户关系管理】12.查询结果分页、排序、过滤组合
- 【CRM客户关系管理】13.为结果添加搜索功能,搜索后能对其进行过滤
- 【CRM客户关系管理】14.生成动态ModelForm表单功能
- 【CRM客户关系管理】15.动态ModelsForm增加自定义样式,修改初始化表单并提交
- 【CRM客户关系管理】16. 只读字段readonly_fields处理,表单排除只读显示
- 【CRM客户关系管理】17.多选字段filter_horizontal的实现,已选和未选数据展示
- 【CRM客户关系管理】18.多选字段filter_horizontal的实现,js移动多选框数据和过滤
- 【CRM客户关系管理】19.对象删除功能,显示删除的关联对象和确认
- 【CRM客户关系管理】20.增加详情页分页功能
- 【CRM客户关系管理】21.action功能开发,默认action,生成自己的action
- 【CRM客户关系管理】22.action功能开发,执行action功能,添加默认的delete action
猜你喜欢
-
Django的F和Q查询使用方法
-
【CRM客户关系管理】15.动态ModelsForm增加自定义样式,修改初始化表单并提交
-
【Vue+DRF生鲜电商】26.使用Pycharm远程代码调试服务器Django代码
-
【keepalived、nginx】CentOS7使用keepalived实现nginx高可用架构
-
【Vue+DRF生鲜电商】13.JWT用户认证原理配置,Vue登录接口调试
-
Django2.1.8升级到2.2.3迁移报错handler403、404问题
-
【Vue+DRF生鲜电商】14.用户注册发送短信验证码、登录字段验证
-
【K8s+Docker技术全解】10.Master主控节点服务-部署kube-scheduler、检查集群状态