CRM项目(四)
CRM项目开发(四)
|
文章目录
2. 添加过滤功能 2.1. 添加过滤字段 2.2. 编写过滤功能函数 2.3. 编写视图函数 2.4. 编写模板文件 2.5. BUG解决 2.6. 优化 |
在上篇文章中,我们仅仅是展示了最基础的表格字段的内容,这篇文章我们来添加过滤功能和分页功能!
添加分页功能
添加分页字段
在king_admin.py文件中添加分页字段,表示每页显示多少内容,如下:
...
#创建基类
class BaseAdmin(object):
list_display = []
list_filter = []
list_per_page = 2 #添加此数据
...
如果我们需要修改每页要显示的内容数量时,同样是在king_admin中,只需要在自定义的子类中添加即可。如下:
#自定义类,显示特定字段
class CustomerAdmin(BaseAdmin):
list_display = ['qq','name','source','consultant','consult_course','date','status']
list_filters = ['source','consultant','consult_course','status']
list_per_page = 2 #添加此数据覆盖基类数据
编写视图函数
在Django中,已经为我们提供了封装好的分页模块,只需要引用即可!具体的使用看看官网的样例就明白了。
啥也不说,直接上代码:
def display_objects(request, app_name, table_name):
#获取自定义的admin_class
admin_class = enabled_admins[app_name][table_name]
#数据查询
#query_set = admin_class.model.objects.all()
#分页处理
#1.分页对象参数构建:对象列表,每页显示数量
query_set_list = admin_class.model.objects.all()
#2.分页对象创建
paginator = Paginator(query_set_list, admin_class.list_per_page)
#3.获取前端点击的页面数值
get_page = request.GET.get('page')
#4.页面异常处理
try:
#直接获取该页内容
query_set = paginator.page(get_page)
except PageNotAnInteger:
#不是整数值,跳转到首页
query_set = paginator.page(1)
except EmptyPage:
#超出范围,跳转到最后一页
query_set = paginator.page(paginator.num_pages)
return render(request, 'king_admin/table_objs.html',
{'admin_class': admin_class,
'query_set': query_set})
编写模板文件
此时,我们需要对二级页面添加一些内容,用于显示分页效果,如下:
{% extends 'king_admin/table_index.html' %}
{% load tags %}
{% block container %}
<div class="panel panel-info">
<div class="panel-heading">
<h3 class="panel-title">Panel title</h3>
</div>
<div class="panel-body">
{#具体的表格内容展示 #}
<table class="table table-hover">
<thead>
<tr>
{% for title_name in admin_class.list_display %}
<th>{{ title_name }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for item in query_set %}
<tr>
{#创建列表行数据#}
{% create_row item admin_class %}
</tr>
{% endfor %}
</tbody>
</table>
<nav>
{#分页处理#}
<ul class="pagination">
{#判断是否有上一页#}
{% if query_set.has_previous %}
<li class=""><a href="?page={{ query_set.previous_page_number }}">上一页</a></li>
{% endif %}
{% create_page_element query_set %}
{#判断是否有下一页#}
{% if query_set.has_next %}
<li class=""><a href="?page={{ query_set.next_page_number }}">下一页</a></li>
{% endif %}
</ul>
</nav>
</div>
</div>
{% endblock %}
标签文件的内容:
from django import template
from django.utils.safestring import mark_safe
register = template.Library()
#------------------------显示表名称-->中文---------------------------
@register.simple_tag
def render_verbose_name(admin_class):
return admin_class.model._meta.verbose_name
#-------------------------创建表格行数据-----------------------------
@register.simple_tag
def create_row(query_set_obj, admin_class):
#创建标签元素--空,None不行
element = ''
#遍历要显示的models字段
for row in admin_class.list_display:
#获取显示字段对应的字段对象
field_obj = admin_class.model._meta.get_field(row)
#获取数据
#判断choice
if field_obj.choices:
#通过反射获取对象里面的值,并执行该方法get_字段_display()获取choices里面的数值
row_data = getattr(query_set_obj, 'get_{0}_display'.format(row))()
else:
row_data = getattr(query_set_obj, row)
#时间格式转换
if type(row_data).__name__ == 'datetime':
row_data = row_data.strftime('%Y-%m-%d %H-%M-%S')
#标签元素的拼接
element += "<td>{0}</td>".format(row_data)
return mark_safe(element)
#-----------------------------分页处理---------------------------------
@register.simple_tag
def create_page_element(query_set):
'''返回整个分页元素'''
page_btns = ''
added_dot_ele = False #标志符
for page_num in query_set.paginator.page_range:
if page_num < 3 or page_num > query_set.paginator.num_pages -2 \
or abs(query_set.number - page_num) <= 2: #代表最前2页或最后2页 #abs判断前后1页
element_class = ""
if query_set.number == page_num:
added_dot_ele = False
element_class = "active"
page_btns += '''<li class="%s"><a href="?page=%s">%s</a></li>''' % (element_class, page_num, page_num)
else: #显示...
if added_dot_ele == False: #现在还没加...
page_btns += '<li><a>...</a></li>'
added_dot_ele = True
return mark_safe(page_btns)
渲染之后的效果:

添加过滤功能
添加过滤字段
同样是在king_admin.py中添加过滤字段,可以自己添加过滤条件,添加内容如下:
...
#创建基类
class BaseAdmin(object):
list_display = []
list_filter = [] #添加此数据
list_per_page = 2
...
如果我们需要修改每页的过滤条件时,同样是在king_admin中,只需要在自定义的子类中添加即可。如下:
#自定义类,显示特定字段
class CustomerAdmin(BaseAdmin):
list_display = ['qq','name','source','consultant','consult_course','date','status']
list_filters = ['source','consultant','consult_course','status'] #添加此数据覆盖基类数据
list_per_page = 2
编写过滤功能函数
将过滤功能独立出来,便于我们对后面的添加的功能更好的结合与修改,在king_admin应用目录下创建utils.py文件,并编写过滤功能函数:
----------------过滤功能------------------------------
def table_filter(request, admin_class):
"""条件过滤,并构造滤后的数据结构"""
filter_conditions = {}
for k, v in request.GET.items():
if v:
filter_conditions[k] = v
return admin_class.model.objects.filter(**filter_conditions), filter_conditions
编写视图函数
在基于分页功能的基础,添加过滤功能:
def display_objects(request, app_name, table_name):
#获取自定义的admin_class
admin_class = enabled_admins[app_name][table_name]
#数据查询
#query_set = admin_class.model.objects.all()
#分页处理
#1.分页对象参数构建:对象列表,每页显示数量
#query_set_list = admin_class.model.objects.all()
#延伸===>添加过滤条件
query_set_list, filter_conditions = table_filter(request, admin_class)
#2.分页对象创建
paginator = Paginator(query_set_list, admin_class.list_per_page)
#3.获取前端点击的页面数值
get_page = request.GET.get('page')
#4.页面异常处理
try:
#直接获取该页内容
query_set = paginator.page(get_page)
except PageNotAnInteger:
#不是整数值,跳转到首页
query_set = paginator.page(1)
except EmptyPage:
#超出范围,跳转到最后一页
query_set = paginator.page(paginator.num_pages)
return render(request, 'king_admin/table_objs.html',
{'admin_class': admin_class,
'query_set': query_set,
'filter_conditions': filter_conditions})
编写模板文件
因为过滤的条件需要提交后台,所以要构建表单,在table_ojs.html文件中添加如下内容:
...
<div class="panel-body">
<div class="row">
<form class="" method="get">
{#条件过滤#}
{% for condition in admin_class.list_filters %}
<div class="col-lg-2">
<span>{{ condition }}</span>
{% render_filter_element condition admin_class filter_conditions %}
</div>
{% endfor %}
<button type="SUBMIT" class="btn btn-success">检索</button>
</form>
</div>
{#具体的表格内容展示 #}
<table class="table table-hover">
...
标签文件内容:
from django import template
from django.utils.safestring import mark_safe
register = template.Library()
#------------------------显示表名称-->中文---------------------------
@register.simple_tag
def render_verbose_name(admin_class):
return admin_class.model._meta.verbose_name
#-------------------------创建表格行数据-----------------------------
@register.simple_tag
def create_row(query_set_obj, admin_class):
#创建标签元素--空,None不行
element = ''
#遍历要显示的models字段
for row in admin_class.list_display:
#获取显示字段对应的字段对象
field_obj = admin_class.model._meta.get_field(row)
#获取数据
#判断choice
if field_obj.choices:
#通过反射获取对象里面的值,并执行该方法get_字段_display()获取choices里面的数值
row_data = getattr(query_set_obj, 'get_{0}_display'.format(row))()
else:
row_data = getattr(query_set_obj, row)
#时间格式转换
if type(row_data).__name__ == 'datetime':
row_data = row_data.strftime('%Y-%m-%d %H-%M-%S')
#标签元素的拼接
element += "<td>{0}</td>".format(row_data)
return mark_safe(element)
#-----------------------------分页处理---------------------------------
@register.simple_tag
def create_page_element(query_set):
'''返回整个分页元素'''
page_btns = ''
added_dot_ele = False #标志符
for page_num in query_set.paginator.page_range:
if page_num < 3 or page_num > query_set.paginator.num_pages -2 \
or abs(query_set.number - page_num) <= 2: #代表最前2页或最后2页 #abs判断前后1页
element_class = ""
if query_set.number == page_num:
added_dot_ele = False
element_class = "active"
page_btns += '''<li class="%s"><a href="?page=%s">%s</a></li>''' % (element_class, page_num, page_num)
else: #显示...
if added_dot_ele == False: #现在还没加...
page_btns += '<li><a>...</a></li>'
added_dot_ele = True
return mark_safe(page_btns)
#--------------------------------过滤条件处理-----------------------------
@register.simple_tag
def render_filter_element(condition, admin_class, filter_conditions):
#初始化下拉框
select_element = """<select class='form-control' name={0}><option value=''>------
</option>""".format(condition)
#获取字段
field_object = admin_class.model._meta.get_field(condition)
#字段处理
# 默认不选中
selected = ''
#choice处理
if field_object.choices:
#遍历choices值
for choice_item in field_object.get_choices()[1:]:
# print(choice_item)
#判断选择条件是否和choice值相等
if filter_conditions.get(condition) == str(choice_item[0]):
#被选中
selected = 'selected'
select_element += """<option value='{0}' {1}>{2}</option>""".format(choice_item[0],
selected, choice_item[1])
selected = ''
#外键处理
if type(field_object).__name__ == 'ForeignKey':
for choice_item in field_object.get_choices()[1:]:
# 判断选择条件是否和choice值相等
if filter_conditions.get(condition) == str(choice_item[0]):
# 被选中
selected = 'selected'
select_element += """<option value='{0}' {1}>{2}</option>""".format(choice_item[0],
selected, choice_item[1])
selected = ''
select_element += '</select>'
return mark_safe(select_element)
渲染后的结果:

BUG解决
搜索后对结果很是满意,分页显示数量也是正确,然而,当点击下一页的时候确调回了初始状态!这是为什么呢??
其实很简单,我们在做分页处理的时候并没有考虑到过滤参数,只需要在分页标签中添加过滤参数到传输数据的url中即可!
标签文件中的分页处理修改如下:
...
@register.simple_tag
def create_page_element(query_set, filter_conditions):
'''返回整个分页元素'''
page_btns = ''
filters = ''
#过滤条件
for k, v in filter_conditions.items():
filters += '&{0}={1}'.format(k, v)
added_dot_ele = False #标志符
for page_num in query_set.paginator.page_range:
if page_num < 3 or page_num > query_set.paginator.num_pages -2 \
or abs(query_set.number - page_num) <= 2: #代表最前2页或最后2页 #abs判断前后1页
element_class = ""
if query_set.number == page_num:
added_dot_ele = False
element_class = "active"
page_btns += '''<li class="%s"><a href="?page=%s%s">%s</a></li>''' % (element_class, page_num, filters ,page_num)
else: #显示...
if added_dot_ele == False: #现在还没加...
page_btns += '<li><a>...</a></li>'
added_dot_ele = True
return mark_safe(page_btns)
...
上述文件中只是将过滤的参数值添加到提交url的标签中。
当然,在模板文件table_objs.html中,我们也要有相应的修改,这里就简单了只需要添加一个参数(filter_conditions)即可:
...
{% create_page_element query_set filter_conditions %}
...
至此,BUG解决了,可以完美的进行过滤,分页啦!
优化
还有一点值得考虑,就是page这个关键字,是否会影响到数据的存储和查询?为了避免这样的隐患存在,我们可以将这个参数作为保留字,不允许在数据库中使用!
那么,该如何实现呢?其实很简答喽,我只需要在过滤功能函数那里添加一个判断就行啦!如下:
#--------------------------过滤功能------------------------------
def table_filter(request, admin_class):
"""条件过滤,并构造滤后的数据结构"""
filter_conditions = {}
keywords = ['page'] #保留关键字
for k, v in request.GET.items():
if k in keywords:
continue
if v:
filter_conditions[k] = v
return admin_class.model.objects.filter(**filter_conditions), filter_conditions
这里我们以列表的形式,便于后期扩展添加其他的保留字!

浙公网安备 33010602011771号