CRM项目(四)

CRM项目开发(四)

文章目录
1. 添加分页功能

  1.1. 添加分页字段

  1.2. 编写视图函数

  1.3. 编写模板文件

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

这里我们以列表的形式,便于后期扩展添加其他的保留字!

posted @ 2017-01-16 17:17  runnering  阅读(245)  评论(0)    收藏  举报