您现在的位置是: 网站首页 >Django >DjangoCRM客户关系管理 Django
【CRM客户关系管理】18.多选字段filter_horizontal的实现,js移动多选框数据和过滤
admin2018年12月23日 15:25 【Django | JavaScript | JQuery | Python 】 1170人已围观
DjangoCRM客户关系管理简介 使用Django2.1.3+Bootstrap实现CRM系统,仿照Django Admin重写后台 Github地址:https://github.com/xyliurui/DjangoCRM Django版本:2.1.3
### js实现多选框数据移动 #### js实现左右多选框移动数据 为左边的select增加一个`id="id_{{ field.name }}_from"`,为右边的select增加一个`id="id_{{ field.name }}_to"`。 为左边的option增加一个双击事件`ondblclick="MoveSelectedOption(this,'id_{{ field.name }}_to')"`,为右边的option增加一个双击事件`ondblclick="MoveSelectedOption(this,'id_{{ field.name }}_from')"`。 查看编辑表单的客户姓名这一栏 ```html <input type="text" name="name" value="测试" maxlength="50" class="form-control" required="" id="id_name"> ``` 以上`{{ field }}`自动生成了id和name等 所以需要在右边的多选框增加`name`字段:`name="{{ field.name }}">` ```html <div class="col-sm-10"> {% if field.name in admin_class.filter_horizontal %} <!--字段名在多选的字段中,使用多选框--> <div class="col-md-5"> <select multiple class="form-control" id="id_{{ field.name }}_from"> {% get_available_m2m_data field.name form_obj admin_class as vailable_m2m_data %} {% for obj in vailable_m2m_data %} <option value="{{ obj.id }}" ondblclick="MoveSelectedOption(this,'id_{{ field.name }}_to')">{{ obj }}</option> {% endfor %} </select> </div> <div class="col-md-5"> <select multiple class="form-control" id="id_{{ field.name }}_to" 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 }}_from')">{{ obj }}</option> {% endfor %} </select> </div> {% else %} {{ field }} {% endif %} <span style="color: red">{{ field.errors.0 }}</span> </div> ``` 然后再`{% endblock %}`块前增加js用于多选框移除移入 ```html <script> function MoveSelectedOption(ele, target_id) { let new_target_id = $(ele).parent().attr('id'); let option = "<option value='" + $(ele).val() +"'ondblclick=MoveSelectedOption(this,'"+ new_target_id +"') >" + $(ele).text() +"</option>"; //将双击的元素添加到另一方 $("#"+ target_id).append(option); //移除本方的元素 $(ele).remove(); } </script> ``` 当双击**咨询课程**左边多选框内的数据,就会移动到右边多选框,当双击右边多选框内的数据,就会移动到左边多选框。 访问 http://127.0.0.1:8000/djadmin/crm/customerinfo/1/change/ ,修改咨询课程,然后提交保存,但会出现以下提示 ![BLOG_20181223_153746_12](/media/blog/images/2018/12/BLOG_20181223_153746_12.png "博客图集BLOG_20181223_153746_12.png") 说明`name="{{ field.name }}">`所在的select中的option没有一个为选中状态 #### js实现提交表单selected已选择数据 修改form表单提交的验证函数调用`<form class="form-horizontal" method="post" onsubmit="VerificationBeforeFormSubmit();">。。。</form` 定义一个提交选中右方所有选项的js函数 ```html <script> function VerificationBeforeFormSubmit() { $("select[myflag] option").prop('selected', true); } </script> ``` 由于这个全选没有一个id或者是class找到右方的多选框,所以自定义一个`myflag="selected_m2m"` ```html <div class="col-md-5"> <select myflag="selected_m2m" multiple class="form-control" id="id_{{ field.name }}_to" 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 }}_from')">{{ obj }}</option> {% endfor %} </select> </div> ``` 现在提交时就会把右方的多选框全选,进行提交。 如果不自定义,如下 ```html <script> function VerificationBeforeFormSubmit() { $("select option").prop('selected', true); } </script> ``` **当表单提交时,所有的选框select--option都会被选中!这就回造成如果有单选框是不能保存。** 最终table_edit.html内容是 ```html {% extends 'djadmin/base.html' %} {% load djadmin_tags %} {% block title %} 数据表编辑 - 后台管理 {% endblock %} {% block content %} <h1 class="page-header">{{ app_name }} - {{ model_name }} - 编辑 {{ obj }} </h1> <!--<div>{{ form_obj }}</div>--> <form class="form-horizontal" method="post" onsubmit="VerificationBeforeFormSubmit();"> {{ 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-md-5"> <select multiple class="form-control" id="id_{{ field.name }}_from"> {% get_available_m2m_data field.name form_obj admin_class as vailable_m2m_data %} {% for obj in vailable_m2m_data %} <option value="{{ obj.id }}" ondblclick="MoveSelectedOption(this,'id_{{ field.name }}_to')">{{ obj }}</option> {% endfor %} </select> </div> <div class="col-md-5"> <select myflag="selected_m2m" multiple class="form-control" id="id_{{ field.name }}_to" 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 }}_from')">{{ obj }}</option> {% endfor %} </select> </div> {% else %} {{ field }} {% endif %} <span style="color: red">{{ field.errors.0 }}</span> </div> </div> {% endfor %} {% csrf_token %} {% if not admin_class.form_add %} {# 当修改数据时,才显示下方只读字段,当增加数据时,下方则不会显示 #} {% for field in admin_class.readonly_fields %} <label class="col-sm-2 control-label">{{ field }}</label> <div class="col-sm-10"> <p>{% get_obj_field_val form_obj field %}</p> </div> {% endfor %} {% endif %} <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-primary">提交</button> </div> </div> </form> <script> function MoveSelectedOption(ele, target_id) { let new_target_id = $(ele).parent().attr('id'); let option = "<option value='" + $(ele).val() +"'ondblclick=MoveSelectedOption(this,'"+ new_target_id +"') >" + $(ele).text() +"</option>"; //将双击的元素添加到另一方 $("#"+ target_id).append(option); //移除本方的元素 $(ele).remove(); } function VerificationBeforeFormSubmit() { //提交表单时选中所有的select $("select[myflag] option").prop('selected', true); } </script> {% endblock %} ``` ![BLOG_20181223_153711_64](/media/blog/images/2018/12/BLOG_20181223_153711_64.png "博客图集BLOG_20181223_153711_64.png") #### 解决添加数据报错问题 现在更新数据就可以用了。但添加数据会报错。 错误提示是`ValueError: "<CustomerInfo: >" needs to have a value for field "id" before this many-to-many relationship can be used.`查看报错位置是模板标签中的`selected_data = getattr(form_obj.instance, field_name).all()`,当修改数据,获取所有的已选择数据,当添加数据时,已选择为空,这儿就会报错,暂时使用`try`来捕获该异常,修改下面的模板标签 ```python @register.simple_tag def get_available_m2m_data(field_name, form_obj, admin_class): """获取多对多字段关联表的所有数据""" field_obj = admin_class.model._meta.get_field(field_name) # 获取字段对象 # consult_courses = models.ManyToManyField(Course, verbose_name='咨询课程') # 多对多关联课程 # 这是一个多对多字段,通过consult_courses对象获取到Course,也就是获取到所有咨询的课程 obj_list = field_obj.related_model.objects.all() obj_list = set(obj_list) # 所有咨询课程的集合 try: selected_data = set(getattr(form_obj.instance, field_name).all()) # 所以已选中课程的即可 except: selected_data = set([]) # 通过集合求差集,得到未选中的自选课程,填充到左边多选框中 return obj_list - selected_data @register.simple_tag def get_selected_m2m_data(field_name, form_obj, admin_class): """获取已选中的多对多数据""" try: selected_data = getattr(form_obj.instance, field_name).all() except: selected_data = set([]) # print(selected_data) return selected_data ``` 现在访问 http://127.0.0.1:8000/djadmin/crm/customerinfo/add/ 不会报错,并且可以正常添加数据 ![BLOG_20181223_153700_17](/media/blog/images/2018/12/BLOG_20181223_153700_17.png "博客图集BLOG_20181223_153700_17.png") #### 添加全选和删除全部功能 ![BLOG_20181223_153642_58](/media/blog/images/2018/12/BLOG_20181223_153642_58.png "博客图集BLOG_20181223_153642_58.png") 修改table_edit.html增加a标签和js函数,用于选择全部,以及移除选择功能 ```html {% if field.name in admin_class.filter_horizontal %} <!--字段名在多选的字段中,使用多选框--> <div class="col-md-5"> <select multiple class="form-control" id="id_{{ field.name }}_from"> {% get_available_m2m_data field.name form_obj admin_class as vailable_m2m_data %} {% for obj in vailable_m2m_data %} <option value="{{ obj.id }}" ondblclick="MoveSelectedOption(this,'id_{{ field.name }}_to')">{{ obj }}</option> {% endfor %} </select> <p><a onclick="MoveAllElements('id_{{ field.name }}_from', 'id_{{ field.name }}_to')">全选></a></p> </div> <div class="col-md-5"> <select myflag="selected_m2m" multiple class="form-control" id="id_{{ field.name }}_to" 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 }}_from')">{{ obj }}</option> {% endfor %} </select> <p><a onclick="MoveAllElements('id_{{ field.name }}_to', 'id_{{ field.name }}_from')"><删除全部</a></p> </div> {% else %} {{ field }} {% endif %} ``` 添加js函数实现该功能 ```html <script> function MoveAllElements(from_id, to_id) { console.log($("#" + from_id).children()) $("#" + from_id).children().each(function () { MoveSelectedOption(this, to_id); }) } </script> ``` 访问 http://127.0.0.1:8000/djadmin/crm/customerinfo/1/change/ 点击删除全部,就会把所有已到左方 ![BLOG_20181223_153628_74](/media/blog/images/2018/12/BLOG_20181223_153628_74.png "博客图集BLOG_20181223_153628_74.png") 点击全选就会把所有移动到右方 ![BLOG_20181223_153608_56](/media/blog/images/2018/12/BLOG_20181223_153608_56.png "博客图集BLOG_20181223_153608_56.png") 添加数据页面功能也正常 ### 多框框过滤功能 类似于Django Admin的选择框所有 #### 创建搜索框 在左方多选框上增加一个`type="search"`的input标签 ```html <div class="col-md-5"> <input type="search" class="form-control" oninput="FuzzySearch(this)" placeholder="模糊搜索"> <select multiple class="form-control" id="id_{{ field.name }}_from"> {% get_available_m2m_data field.name form_obj admin_class as vailable_m2m_data %} {% for obj in vailable_m2m_data %} <option value="{{ obj.id }}" ondblclick="MoveSelectedOption(this,'id_{{ field.name }}_to')">{{ obj }}</option> {% endfor %} </select> <p><a onclick="MoveAllElements('id_{{ field.name }}_from', 'id_{{ field.name }}_to')">全选></a></p> </div> ``` #### js实现搜索过滤 ```html <script> function FuzzySearch(ele) { //过滤多选框中的数据 console.log($(ele).val()); let search_text = $(ele).val().toUpperCase(); $(ele).next().children().each(function () { if ($(this).text().toUpperCase().search(search_text) !== -1) { $(this).show(); } else { $(this).hide(); } }) } </script> ``` 现在在输入框中输入值就会过滤下方的多选框内容。 ![BLOG_20181223_153558_39](/media/blog/images/2018/12/BLOG_20181223_153558_39.png "博客图集BLOG_20181223_153558_39.png") ![BLOG_20181223_153537_12](/media/blog/images/2018/12/BLOG_20181223_153537_12.png "博客图集BLOG_20181223_153537_12.png") 最终table_edit.html代码如下 ```html {% extends 'djadmin/base.html' %} {% load djadmin_tags %} {% block title %} 数据表编辑 - 后台管理 {% endblock %} {% block content %} <h1 class="page-header">{{ app_name }} - {{ model_name }} - 编辑 {{ obj }} </h1> <!--<div>{{ form_obj }}</div>--> <form class="form-horizontal" method="post" onsubmit="VerificationBeforeFormSubmit();"> {{ 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-md-5"> <input type="search" class="form-control" oninput="FuzzySearch(this)" placeholder="模糊搜索"> <select multiple class="form-control" id="id_{{ field.name }}_from"> {% get_available_m2m_data field.name form_obj admin_class as vailable_m2m_data %} {% for obj in vailable_m2m_data %} <option value="{{ obj.id }}" ondblclick="MoveSelectedOption(this,'id_{{ field.name }}_to')">{{ obj }}</option> {% endfor %} </select> <p><a onclick="MoveAllElements('id_{{ field.name }}_from', 'id_{{ field.name }}_to')">全选></a></p> </div> <div class="col-md-5"> <select myflag="selected_m2m" multiple class="form-control" id="id_{{ field.name }}_to" 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 }}_from')">{{ obj }}</option> {% endfor %} </select> <p><a onclick="MoveAllElements('id_{{ field.name }}_to', 'id_{{ field.name }}_from')"> <删除全部 </a></p> </div> {% else %} {{ field }} {% endif %} <span style="color: red">{{ field.errors.0 }}</span> </div> </div> {% endfor %} {% csrf_token %} {% if not admin_class.form_add %} {# 当修改数据时,才显示下方只读字段,当增加数据时,下方则不会显示 #} {% for field in admin_class.readonly_fields %} <label class="col-sm-2 control-label">{{ field }}</label> <div class="col-sm-10"> <p>{% get_obj_field_val form_obj field %}</p> </div> {% endfor %} {% endif %} <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-primary">提交</button> </div> </div> </form> <script> function MoveSelectedOption(ele, target_id) { let new_target_id = $(ele).parent().attr('id'); let option = "<option value='" + $(ele).val() + "'ondblclick=MoveSelectedOption(this,'" + new_target_id + "') >" + $(ele).text() + "</option>"; //将双击的元素添加到另一方 $("#" + target_id).append(option); //移除本方的元素 $(ele).remove(); } function VerificationBeforeFormSubmit() { //提交表单时选中所有的select $("select option").prop('selected', true); } function MoveAllElements(from_id, to_id) { console.log($("#" + from_id).children()) $("#" + from_id).children().each(function () { MoveSelectedOption(this, to_id); }) } function FuzzySearch(ele) { //过滤多选框中的数据 console.log($(ele).val()); let search_text = $(ele).val().toUpperCase(); $(ele).next().children().each(function () { if ($(this).text().toUpperCase().search(search_text) !== -1) { $(this).show(); } else { $(this).hide(); } }) } </script> {% endblock %} ```
很赞哦! (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