CRM客户关系管理系统(八) 第八章、只读字段处理和filter_horizontal的实现

第八章、只读字段处理和filter_horizontal的实现

 8.1.只读字段的处理

(1)kingadmin/admin_base.py

# kingadmin/admin_base.py

class BaseKingAdmin(object):

    list_display = []
    list_filter = []
    search_fields = []
    #只读
    readonly_fields = []

(2)crm/kingadmin.py

 (3)kingadmin/form_handle.py

 (4)table_obj_change_component.html

{#kingadmin/templates/kingadmin/table_obj_change_component.html#}

{% load kingadmin_tags %}
<form class="form-horizontal" method="post">
    {% csrf_token %}
    {{ form_obj.errors }}
    {% for field in form_obj %}
    <div class="form-group">
        <label class="col-sm-2 control-label">{{ field.label }}</label>
        <div class="col-sm-10">
            {{ field }}
            <span style="color: red;">{{ field.errors.0 }}</span>
        </div>
    </div>
    {% endfor %}
    
    {% for field in admin_class.readonly_fields %}
    <div class="form-group">
        <label class="col-sm-2 control-label">{{ field }}</label>
        <div class="col-sm-10">
            <p>{% get_obj_field_val form_obj field %}</p>
        </div>
    </div>
    {% endfor %}


    <div class="form-group">
        <div class="col-sm-offset-11 col-sm-10">
          <button type="submit" class="btn btn-info">Save</button>
        </div>
    </div>
</form>

 (5)kingadmin_tags.py

@register.simple_tag
def get_obj_field_val(form_obj,field):
    '''获取只读字段的值'''

    return getattr(form_obj.instance,field)

现在修改的时候没问题,但是在添加的时候会报错(提示那两个只读字段为空,因为设置成了readonly_field,添加的时候确实没有添加值)

下面解决这个报错,在前后端都添加一个判断

(4)kingadmin/views.py

(5)form_handle.py

 (6)table_obj_change_component.html

现在增加和修改就都没问题了

8.2.filter_horizontal的实现

默认咨询课程后台显示的样子

 添加filter_horizontal(数据量大的时候很方便)后显示的样子(可以批量添加,还可以在里面搜索)

 下面我们在kingadmin中实现这个功能

 (1)kingadmin/admin_base.py

# kingadmin/admin_base.py

class BaseKingAdmin(object):

    list_display = []
    list_filter = []
    search_fields = []
    #只读
    readonly_fields = []
    filter_horizontal = []

(2)crm/kingadmin.py

 (3)kingadmin/kingadmin_tags.py

@register.simple_tag
def get_available_m2m_data(field_name,admin_class):
    '''返回的是m2m字段关联表的所有数据'''
    #获取字段的对象
    field_obj = admin_class.model._meta.get_field(field_name)

    #consult_courses = models.ManyToManyField('Course',verbose_name='咨询课程')
    #consult_courses是一个m2m,通过consult_courses对象获取到Course(也就是获取到所有咨询的课程)
    obj_list = field_obj.related_model.objects.all()

    return obj_list

(4)table_obj_change_component.html

  •  在生成field的时候判断在不在filter_horizontal里面,在的话就用我们设置的select下拉框,不在就默认的
  •  {% get_available_m2m_data field.name admin_class as available_m2m_data %}  后面的的 as availavle_m2m_data 是定义一个变量(里面存了自定义模板标签里面返回的数据 return obj_list

    因为在前端不能直接循环从后台返回的querysets数据(obj_list),所以前端在引用自定用模板标签的时候可以定义一个变量,里面就保存了所有后台传过来的数据

{#kingadmin/templates/kingadmin/table_obj_change_component.html#}

{% load kingadmin_tags %}
<form class="form-horizontal" method="post">
    {% csrf_token %}
    {{ form_obj.errors }}
    {% for field in form_obj %}
    <div class="form-group">
        <label class="col-sm-2 control-label">{{ field.label }}</label>
        <div class="col-sm-10">
            {% if field.name in admin_class.filter_horizontal %}
                <div class="col-lg-5">
                    <select multiple class="form-control">
                        {% get_available_m2m_data field.name admin_class as available_m2m_data %}
                        {% for obj in available_m2m_data %}
                            <option value="{{ obj.id }}">{{ obj }}</option>
                        {% endfor %}
                    </select>
                </div>
                <div class="col-lg-5"></div>
            {% else %}
                {{ field }}
            {% endif %}
            <span style="color: red;">{{ field.errors.0 }}</span>
        </div>
    </div>
    {% endfor %}

 效果:

 右边添加一个select框(存放已选中的)

 kingadmin_tags.py

@register.simple_tag
def get_selected_m2m_data(field_name,form_obj,admin_class):
    '''返回已选的m2m数据'''
    #获取被选中的数据
    selected_data = getattr(form_obj.instance,field_name).all()

    return selected_data

table_obj_change_component.html

<div class="col-lg-5">
                    <select multiple class="form-control">
                        {% get_selected_m2m_data field.name form_obj admin_class as selected_m2m_data %}
                        {% for obj in selected_m2m_data %}
                            <option value="{{ obj.id }}">{{ obj }}</option>
                        {% endfor %}
                    </select>
                </div>

效果:

  • 左边不应该显示已被选中的咨询课程了
  • 右边是已选中的咨询课程

通过集合求差集过滤出左边已选咨询课程

 kingadmin_tags.py

@register.simple_tag
def get_available_m2m_data(field_name,form_obj,admin_class):
    '''返回的是m2m字段关联表的所有数据'''
    #获取字段的对象
    field_obj = admin_class.model._meta.get_field(field_name)
    #consult_courses = models.ManyToManyField('Course',verbose_name='咨询课程')
    #consult_courses是一个m2m,通过consult_courses对象获取到Course(也就是获取到所有咨询的课程)
    #所有咨询课程的集合
    obj_list = set(field_obj.related_model.objects.all())
    #选中的咨询课程集合
    selected_data = set(getattr(form_obj.instance, field_name).all())
    #返回的时候,集合求差集,得到未选中的咨询课程(左边)
    return obj_list - selected_data

效果:

js触发事件

table_obj_change_component.html

可以通过双击咨询课程,来选择

{#kingadmin/templates/kingadmin/table_obj_change_component.html#}

{% load kingadmin_tags %}
<form class="form-horizontal" method="post" onsubmit="VerficationBeforeSubmit()">
    {% csrf_token %}
    {{ form_obj.errors }}
    {% for field in form_obj %}
    <div class="form-group">
        <label class="col-sm-2 control-label">{{ field.label }}</label>
        <div class="col-sm-10">
            {% if field.name in admin_class.filter_horizontal %}
                <div class="col-lg-5">
                    <select id="id_{{ field.name }}_from" multiple class="form-control">
                        {% get_available_m2m_data field.name form_obj admin_class as available_m2m_data %}
                        {% for obj in available_m2m_data %}
                            <option value="{{ obj.id }}" ondblclick="MoveSelectedOption(this,'id_{{ field.name }}_to')">{{ obj }}</option>
                        {% endfor %}
                    </select>
                </div>

                <div class="col-lg-5">
                    <select tag="selected_m2m" id="id_{{ field.name }}_to" multiple class="form-control" name="{{ field.name }}">
                        {% get_selected_m2m_data field.name form_obj admin_class as selected_m2m_data %}
                        {% for obj in selected_m2m_data %}
                            <option value="{{ obj.id }}" ondblclick="MoveSelectedOption(this,'id_{{ field.name }}_fromm')">{{ obj }}</option>
                        {% endfor %}
                    </select>
                </div>
            {% else %}
                {{ field }}
            {% endif %}
            <span style="color: red;">{{ field.errors.0 }}</span>
        </div>
    </div>
    {% endfor %}

    {% if not admin_class.form_add %}     <!--如果是修改表单-->
        {% for field in admin_class.readonly_fields %}
        <div class="form-group">
            <label class="col-sm-2 control-label">{{ field }}</label>
            <div class="col-sm-10">
                <p>{% get_obj_field_val form_obj field %}</p>
            </div>
        </div>
        {% endfor %}
    {% endif %}

    <div class="form-group">
        <div class="col-sm-offset-11 col-sm-10">
          <button type="submit" class="btn btn-info">Save</button>
        </div>
    </div>
</form>

<script>

    function MoveSelectedOption(ele,target_id){

        var new_target_id = $(ele).parent().attr('id');
        var option = "<option value='" +$(ele).val() +"'ondblclick=MoveSelectedOption(this,'"+new_target_id+"')>" + $(ele).text() + "</option>";
        $("#"+ target_id).append(option);
        $(ele).remove();
    }

    function VerficationBeforeSubmit() {

        $("select[tag] option").prop("selected",true);
    }
</script>

现在保存的时候没有问题,但是 添加的时候会报错(因为添加的时候,值都是为空,获取不到filter_horizontal的值所有报错),下一章解决

代码已同步     num8 只读字段的处理;filter_horizontal的实现

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Fundebug

抛弃console.log(),拥抱浏览器Debugger

为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。

1343
来自专栏一个会写诗的程序员的博客

一篇文章读懂 React and redux 前端开发 -DvaJS, a lightweight and elm-style framework.快速上手Dva 概念 #例子和脚手架Dva 图解K

DvaJS: React and redux based, lightweight and elm-style framework.

1813
来自专栏魏艾斯博客www.vpsss.net

代码实现 WordPress 文章中英文数字间自动添加空格

2523
来自专栏小狼的世界

学习使用YUI3

对YUI一直很有好感,最近开始看了看YUI CSS GRID,发现这个理念非常好,非常有利于我们工作效率的提高,特别是熟悉了这套CSS之后,我们就不必每一个项目...

832
来自专栏更流畅、简洁的软件开发方式

【开源】QuickPager 分页控件的内部结构,和OO原则与设计模式

关键字:提出需求、需求分析、原则、设计模式、索引      先说一下讨论的范围:使用数据库保存信息的项目,b/s结构,asp.net编写。请不要讨论这个范围之外...

2126
来自专栏DeveWork

WordPress删除头部wp_head()多余代码

如果你有查看过你的WordPress博客的“查看源代码”的话,你会发现头部的html代码非常多,而且是密密麻麻,有些像meta name="generator"...

8967
来自专栏深度学习之tensorflow实战篇

python2.7进行爬虫POI代码(划分小网格算法)

查询许久,最终选择一个,之前一直py3.6不成功,换了2.7就好多了。如果有重复去下重即可。 这里面非常重要的基类对象的init()方法与超类方法,将在下面进行...

28111
来自专栏云飞学编程

Python爬虫学习,记一次抓包获取js,从js函数中取数据的过程

昨天有小伙伴找我,新浪新闻的国内新闻页,其他部分都是静态网页可以抓到,但是在左下方的最新新闻部分,不是静态网页,也没有json数据,让我帮忙抓一下。大概看了下,...

3471
来自专栏技术博文

关于微信二次分享,标题变链接的解决方法(二)----代码部分

声明: 本篇博文只是个人工作中的分享总结,仅代表个人观点,虽然解决了不少网友的问题,但同时也引来了一些网友的不满,所以特此声明,当您遇到本博文解决不了的问题,可...

3666
来自专栏向前进

【踩坑】activiti工作流的svg-xml解析报错

1、问题记录   工作流配置画模板的时候保存成功但是部署报错。   IE下 activiti工作流解析xml报错 type "path" must be fol...

3944

扫码关注云+社区

领取腾讯云代金券