美文网首页Python Web开发学习
【CRM客户关系管理】09.根据模型中字段的choices以及时

【CRM客户关系管理】09.根据模型中字段的choices以及时

作者: 吾星喵 | 来源:发表于2018-11-26 11:12 被阅读0次

    个人博客,欢迎查看:https://blog.starmeow.cn/

    Github地址:https://github.com/xyliurui/DjangoCRM

    添加过滤功能

    先看使用方法,如何获得选项的值

    from crm import models
    x = models.CustomerInfo._meta.get_field('status')
    x
    <django.db.models.fields.SmallIntegerField: status>
    x.choices
    ((1, '未报名'), (2, '已报名'), (3, '结业'))
    x.get_choices()
    [('', '---------'), (1, '未报名'), (2, '已报名'), (3, '结业')]
    

    添加过滤的模板标签

    @register.simple_tag
    def build_option_filter(filter_field, admin_class):
        select = "<select name='{}'>".format(filter_field)
        # 获取列中的字段对象
        filter_field_obj = admin_class.model._meta.get_field(filter_field)
        for choice in filter_field_obj.get_choices():
            option = "<option value='{}'>{}</option>".format(choice[0], choice[1])
            select += option
        select += "</select>"
        return mark_safe(select)
    

    table_detail.html页面增加过滤表单

    {% extends 'djadmin/base.html' %}
    
    {% load djadmin_tags %}
    
    {% block title %}
        数据表详情 - 后台管理
    {% endblock %}
    
    {% block content %}
        <h1 class="page-header">应用 - {{ app_name }}</h1>
        {{ queryset }}
        <p>
            <form>
                {% for filter_field in admin_class.list_filter %}
                    {% build_option_filter filter_field admin_class %}
                {% endfor %}
                <button type="submit">过滤</button>
            </form>
        </p>
        <table class="table table-striped">
            <thead>
            <tr>
                <!--
                {% for display_field in admin_class.list_display %}
                    <th>{{ display_field }}</th>
                {% endfor %}
                -->
                {% build_table_head_name admin_class %}
            </tr>
            </thead>
            <tbody>
                {% for obj in queryset %}
                    <tr>
                        {% build_table_body obj admin_class %}
                    </tr>
                {% endfor %}
            </tbody>
        </table>
    {% endblock %}
    

    刷新 http://127.0.0.1:8000/djadmin/crm/customerinfo/ 页面,会出现错误

    AttributeError at /djadmin/crm/customerinfo/
    'NoneType' object has no attribute 'model'
    

    这是因为时间的过滤方式不对,在crm应用的CustomerInfoAdmin(BaseDjAdmin)类中去掉过去时间,就会正常显示了

    image.png

    但是不能这样做,接下来就来获取这个异常,然后用另外的方式处理时间过滤

    处理过滤模板标签中的时间字段选项

    继续修改build_option_filter(filter_field, admin_class)函数

    @register.simple_tag
    def build_option_filter(filter_field, admin_class):
        select = "<select name='{}'>".format(filter_field)
        # 获取列中的字段对象
        filter_field_obj = admin_class.model._meta.get_field(filter_field)
        try:
            for choice in filter_field_obj.get_choices():
                option = "<option value='{}'>{}</option>".format(choice[0], choice[1])
                select += option
        except AttributeError as e:
            # print(filter_field_obj.get_internal_type())  # 这儿得到的结果是:DateField
            if filter_field_obj.get_internal_type() in ('DateField', 'DateTimeField'):
                import datetime
                now_time = datetime.datetime.now()
                filter_time_list = [
                    ('', '所有时间'),
                    (now_time, '今天'),
                    (now_time - datetime.timedelta(7), '7天内'),  # 往前7天
                    (now_time.replace(day=1), '本月'),  # 本月内
                    (now_time - datetime.timedelta(90), '三个月内'),
                    (now_time.replace(month=1, day=1), '本年'),
                ]
                for dt in filter_time_list:
                    option = "<option value='{}'>{}</option>".format(dt[0], dt[1])
                    select += option
        select += "</select>"
        return mark_safe(select)
    

    视图中处理过滤结果

    首先定义一个过滤函数,与获取request的值,然后对传入的查询集进行过滤,最后返回,视图中只需要调用这个过滤函数

    def get_filter_result(request, queryset):
        """获取过滤的字段,并返回过滤后的查询集和过滤的字典"""
        filter_conditions = {}
        # 获取过滤的字段
        for k, v in request.GET.items():
            if v:  # 所选的值不会空是保存到字典中
                filter_conditions[k] = v
        return queryset.filter(**filter_conditions), filter_conditions
    
    
    @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
    
        return render(request, 'djadmin/table_detail.html', locals())
    

    处理模板标签中过滤选中

    当选择过滤条件后,给对应值添加选中状态 selected=selected

    @register.simple_tag
    def build_option_filter(filter_field, admin_class):
        select = "<select name='{}'>".format(filter_field)
        # 获取列中的字段对象
        filter_field_obj = admin_class.model._meta.get_field(filter_field)
        try:
            for choice in filter_field_obj.get_choices():  # choice[0]为选项的值,choice[1]为选中的可见内容
                # 获取过滤字典中的值,并在模板中呈选中状态
                selected = ''
                if filter_field in admin_class.filter_conditions:
                    # 如果当前值被选中
                    if str(choice[0]) == admin_class.filter_conditions.get(filter_field):
                        selected = 'selected'
    
                option = "<option value='{}' {}>{}</option>".format(choice[0], selected, choice[1])
                select += option
        except AttributeError as e:
            # print(filter_field_obj.get_internal_type())  # 这儿得到的结果是:DateField
            if filter_field_obj.get_internal_type() in ('DateField', 'DateTimeField'):
                import datetime
                now_time = datetime.datetime.now()
                filter_time_list = [
                    ('', '所有时间'),
                    (now_time, '今天'),
                    (now_time - datetime.timedelta(7), '7天内'),  # 往前7天
                    (now_time.replace(day=1), '本月'),  # 本月内
                    (now_time - datetime.timedelta(90), '三个月内'),
                    (now_time.replace(month=1, day=1), '本年'),
                ]
                for dt in filter_time_list:
                    option = "<option value='{}'>{}</option>".format(dt[0], dt[1])
                    select += option
        select += "</select>"
        return mark_safe(select)
    
    image.png

    这时链接变成了 http://127.0.0.1:8000/djadmin/crm/customerinfo/?source=2&consultant=&status=1&created_time=

    处理过滤时间报错问题

    在过滤时间时会报错

    ValidationError at /djadmin/crm/customerinfo/
    ['’2018-11-10 16:53:18.818027‘ 必须为合法的日期格式,请使用 YYYY-MM-DD 格式。']
    

    继续修改build_option_filter(filter_field, admin_class)模板标签,将时间进行格式化,并增加选中功能

    @register.simple_tag
    def build_option_filter(filter_field, admin_class):
        select = "<select name='{}'>".format(filter_field)
        # 获取列中的字段对象
        filter_field_obj = admin_class.model._meta.get_field(filter_field)
        try:
            for choice in filter_field_obj.get_choices():  # choice[0]为选项的值,choice[1]为选中的可见内容
                # 获取过滤字典中的值,并在模板中呈选中状态
                selected = ''
                if filter_field in admin_class.filter_conditions:
                    # 如果当前值被选中
                    if str(choice[0]) == admin_class.filter_conditions.get(filter_field):
                        selected = 'selected'
    
                option = "<option value='{}' {}>{}</option>".format(choice[0], selected, choice[1])
                select += option
        except AttributeError as e:
            # print(filter_field_obj.get_internal_type())  # 这儿得到的结果是:DateField
            if filter_field_obj.get_internal_type() in ('DateField', 'DateTimeField'):
                import datetime
                now_time = datetime.datetime.now()
                filter_time_list = [
                    ('', '所有时间'),
                    (now_time, '今天'),
                    (now_time - datetime.timedelta(7), '7天内'),  # 往前7天
                    (now_time.replace(day=1), '本月'),  # 本月内
                    (now_time - datetime.timedelta(90), '三个月内'),
                    (now_time.replace(month=1, day=1), '本年'),
                ]
                for dt in filter_time_list:
                    # 如果选择的时间值不为空,则进行时间格式化
                    time_to_str = '' if not dt[0] else dt[0].strftime('%Y-%m-%d')  # 需要将时间格式化成:YYYY-MM-DD
    
                    # 设置选中
                    selected = ''
                    if filter_field in admin_class.filter_conditions:
                        # 如果当前值被选中
                        if time_to_str == admin_class.filter_conditions.get(filter_field):
                            selected = 'selected'
    
                    option = "<option value='{}' {}>{}</option>".format(time_to_str, selected, dt[1])
                    select += option
        select += "</select>"
        return mark_safe(select)
    
    image.png

    现在不会报错了,但是除了今天的日期过滤,其他区间日期都不能正常过滤

    image.png

    处理过滤时间数据为空的问题

    因为其它条件过滤的时候值是等于,但是根据时间过滤应该是大于等于才对

    继续修改build_option_filter(filter_field, admin_class)函数,将处理时间的选项name改为{}__gte大于等于select = "<select name='{}__gte'>".format(filter_field),同时修改选中的判断

    @register.simple_tag
    def build_option_filter(filter_field, admin_class):
        select = "<select name='{}'>".format(filter_field)
        # 获取列中的字段对象
        filter_field_obj = admin_class.model._meta.get_field(filter_field)
        try:
            for choice in filter_field_obj.get_choices():  # choice[0]为选项的值,choice[1]为选中的可见内容
                # 获取过滤字典中的值,并在模板中呈选中状态
                selected = ''
                if filter_field in admin_class.filter_conditions:
                    # 如果当前值被选中
                    if str(choice[0]) == admin_class.filter_conditions.get(filter_field):
                        selected = 'selected'
    
                option = "<option value='{}' {}>{}</option>".format(choice[0], selected, choice[1])
                select += option
        except AttributeError as e:
            # 对时间使用单独的select
            select = "<select name='{}__gte'>".format(filter_field)
            # print(filter_field_obj.get_internal_type())  # 这儿得到的结果是:DateField
            if filter_field_obj.get_internal_type() in ('DateField', 'DateTimeField'):
                import datetime
                now_time = datetime.datetime.now()
                filter_time_list = [
                    ('', '所有时间'),
                    (now_time, '今天'),
                    (now_time - datetime.timedelta(7), '7天内'),  # 往前7天
                    (now_time.replace(day=1), '本月'),  # 本月内
                    (now_time - datetime.timedelta(90), '三个月内'),
                    (now_time.replace(month=1, day=1), '本年'),
                ]
                for dt in filter_time_list:
                    # 如果选择的时间值不为空,则进行时间格式化
                    time_to_str = '' if not dt[0] else dt[0].strftime('%Y-%m-%d')  # 需要将时间格式化成:YYYY-MM-DD
                    # 修改name后,过滤时间的参数变成了created_time__gte=2018-11-03,所以下方的选中,需要进行修改
    
                    # 设置选中
                    selected = ''
                    if filter_field + '__gte' in admin_class.filter_conditions:
                        # 如果当前值被选中
                        if time_to_str == admin_class.filter_conditions.get(filter_field + '__gte'):
                            selected = 'selected'
    
                    option = "<option value='{}' {}>{}</option>".format(time_to_str, selected, dt[1])
                    select += option
        select += "</select>"
        return mark_safe(select)
    
    image.png

    修改过滤选项和按钮的样式

    修改table_detail.html增加form的样式

    <p>
        <form class="navbar-form navbar-left">
            {% for filter_field in admin_class.list_filter %}
                {% build_option_filter filter_field admin_class %}
            {% endfor %}
            <button type="submit" class="btn btn-primary">过滤</button>
        </form>
    </p>
    

    然后修改build_option_filter(filter_field, admin_class)模板标签中select样式,两处修改

    # ......
    select = "<select name='{}' class='form-control'>".format(filter_field)
    # ......
    select = "<select  class='form-control' name='{}__gte'>".format(filter_field)
    # ......
    

    最终显示如下

    image.png

    相关文章

      网友评论

        本文标题:【CRM客户关系管理】09.根据模型中字段的choices以及时

        本文链接:https://www.haomeiwen.com/subject/vknvqqtx.html