第八章、只读字段处理和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="VerificationBeforeFormSubmit()"> {% 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 ondblclick="MoveSelectedOption(this,'id_{{ field.name }}_to')" value="{{ obj.id }}">{{ 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 }}_from')">{{ 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-2">
<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 VerificationBeforeFormSubmit() { $("select[tag] option").prop('selected',true); }
</script>

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

CRM客户关系管理系统(八)的更多相关文章

  1. Django CRM客户关系管理系统

    CRM需求分析 随着信息化时代带来的科技创新,CRM客户关系管理系统带来的效益在已经成为很多企业提高竞争优势的一分部,CRM客户关系管理系统将企业管理和客户关系管理集成到统一的平台,其系统功能主要体现 ...

  2. CRM 客户关系管理系统

    CRM(Customer Relationship Manager)客户关系管理系统 企业为提高核心竞争力,利用相应的信息技术以及互联网技术协调企业与顾客间在销售.营销和服务上的交互,从而提升其管理方 ...

  3. CRM客户关系管理系统 北京易信软科信息技术有限公司

    北京易信软科信息技术有限公司 推出大型erp系统,库存管理系统,客户关系管理系统,车辆登记管理系统,员工管理系统,采购管理系统,销售管理系统,为您的企业提供最优质的产品服务 北京易信软科您可信赖的北京 ...

  4. CRM客户关系管理系统-需求概设和详设

    大概设计 大概设计就是对需求进行一个整体性分析,把需要实现的功能都列出来,对于客户关系管理系统,我们需要从角色出发,从而确定有哪些需求,最好是画个思维导图 首先我们是为培训学校这么一个场景来开发的,所 ...

  5. CRM客户关系管理系统有哪些优缺点?

    CRM系统不仅仅是一种技术,也是面向企业的客户管理系统.客户关系管理软件可以帮助销售员快速地找到客户信息,帮助销售员跟踪客户直到完成订单.为提高企业销售效率,CRM被越来越多的企业所采用. 那么,作为 ...

  6. CRM客户关系管理系统(一)

    第一章.CRM介绍和开发流程 1.1.CRM简介 客户关系管理(CRM) 客户关系管理(customer relationship management)的定义是:企业为提高核心竞争力,利用相应的信息 ...

  7. Django项目:CRM(客户关系管理系统)--84--74PerfectCRM实现CRM权限和权限组限制访问URL

    #models.py # ————————01PerfectCRM基本配置ADMIN———————— from django.db import models # Create your models ...

  8. Django项目:CRM(客户关系管理系统)--85--75PerfectCRM实现CRM扩展权限

    # sales_urls.py # ————————47PerfectCRM实现CRM客户报名流程———————— from django.conf.urls import url from bpm. ...

  9. Django项目:CRM(客户关系管理系统)--82--72PerfectCRM实现CRM动态菜单和角色

    #models.py # ————————01PerfectCRM基本配置ADMIN———————— from django.db import models # Create your models ...

  10. Django项目:CRM(客户关系管理系统)--73--63PerfectCRM实现CRM讲师下载作业

    # teacher_urls.py # ————————62PerfectCRM实现CRM讲师讲课记录———————— from django.conf.urls import url from bp ...

随机推荐

  1. python基础—函数装饰器

    python基础-函数装饰器 1.什么是装饰器 装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能. 装饰器的返回值是也是一个函数对象. 装饰器经常用于有切 ...

  2. 从感知机到 SVM,再到深度学习(三)

        这篇博文详细分析了前馈神经网络的内容,它对应的函数,优化过程等等.     在上一篇博文中已经完整讲述了 SVM 的思想和原理.讲到了想用一个高度非线性的曲线作为拟合曲线.比如这个曲线可以是: ...

  3. [Kaggle] dogs-vs-cats之制作数据集[1]

    Step 0:导入必要的库 import tensorflow as tfimport os Step 1:获取图片文件名以及对应的标签 首先是读取给定路径下所有图片的名称以及对应的标签.os.lis ...

  4. 07、NetCore2.0依赖注入(DI)之生命周期

    07.NetCore2.0依赖注入(DI)之生命周期 NetCore2.0依赖注入框架(DI)是如何管理注入对象的生命周期的?生命周期有哪几类,又是在哪些场景下应用的呢? -------------- ...

  5. filter过滤器与map映射

    filter过滤器 >>> list(filter(None,[0,1,2,True,False])) [1, 2, True] filter的作用就是后面的数据按照前面的表达式运算 ...

  6. PhantomJS命令行选项

    支持命令行选项有: --help或-h列出所有可能的命令行选项.立即停止,不会运行一个脚本作为参数传递. --version或-v打印的版本PhantomJS.立即停止,不会运行一个脚本作为参数传递. ...

  7. 最新的Windows环境搭建zeroMQ并使用java代码运行zeromq详细教程

    最近项目要用zeromq,linux上很好配置使用,但是windows上配置与使用没有找到合适的解决方案,看的很头疼,这里自己总结下供大家参考 准备工作: 1.libzmq下载地址:https://g ...

  8. 解决有关flask-socketio中服务端和客户端回调函数callback参数的问题(全网最全)

    由于工作当中需要用的flask_socketio,所以自己学习了一下如何使用,查阅了有关文档,当看到回调函数callback的时候,发现文档里都描述的不太清楚,最后终于琢磨出来了,分享给有需要的朋友 ...

  9. Kylin系列之二:原理介绍

    Kylin系列之二:原理介绍 2018年4月15日 15:52 因何而生 Kylin和hive的区别 1. hive主要是离线分析平台,适用于已经有成熟的报表体系,每天只要定时运行即可. 2. Kyl ...

  10. Git的安装和使用(托管至GitHub的方法)

    一.下载Git 1.下载 下载地址: https://git-scm.com/download/win 根据你的操作系统选择32位或者64位 2.安装过程一路next 3.检验安装是否成功 在桌面点击 ...