CRM客户关系管理系统(八)
第八章、只读字段处理和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客户关系管理系统(八)的更多相关文章
- Django CRM客户关系管理系统
CRM需求分析 随着信息化时代带来的科技创新,CRM客户关系管理系统带来的效益在已经成为很多企业提高竞争优势的一分部,CRM客户关系管理系统将企业管理和客户关系管理集成到统一的平台,其系统功能主要体现 ...
- CRM 客户关系管理系统
CRM(Customer Relationship Manager)客户关系管理系统 企业为提高核心竞争力,利用相应的信息技术以及互联网技术协调企业与顾客间在销售.营销和服务上的交互,从而提升其管理方 ...
- CRM客户关系管理系统 北京易信软科信息技术有限公司
北京易信软科信息技术有限公司 推出大型erp系统,库存管理系统,客户关系管理系统,车辆登记管理系统,员工管理系统,采购管理系统,销售管理系统,为您的企业提供最优质的产品服务 北京易信软科您可信赖的北京 ...
- CRM客户关系管理系统-需求概设和详设
大概设计 大概设计就是对需求进行一个整体性分析,把需要实现的功能都列出来,对于客户关系管理系统,我们需要从角色出发,从而确定有哪些需求,最好是画个思维导图 首先我们是为培训学校这么一个场景来开发的,所 ...
- CRM客户关系管理系统有哪些优缺点?
CRM系统不仅仅是一种技术,也是面向企业的客户管理系统.客户关系管理软件可以帮助销售员快速地找到客户信息,帮助销售员跟踪客户直到完成订单.为提高企业销售效率,CRM被越来越多的企业所采用. 那么,作为 ...
- CRM客户关系管理系统(一)
第一章.CRM介绍和开发流程 1.1.CRM简介 客户关系管理(CRM) 客户关系管理(customer relationship management)的定义是:企业为提高核心竞争力,利用相应的信息 ...
- Django项目:CRM(客户关系管理系统)--84--74PerfectCRM实现CRM权限和权限组限制访问URL
#models.py # ————————01PerfectCRM基本配置ADMIN———————— from django.db import models # Create your models ...
- Django项目:CRM(客户关系管理系统)--85--75PerfectCRM实现CRM扩展权限
# sales_urls.py # ————————47PerfectCRM实现CRM客户报名流程———————— from django.conf.urls import url from bpm. ...
- Django项目:CRM(客户关系管理系统)--82--72PerfectCRM实现CRM动态菜单和角色
#models.py # ————————01PerfectCRM基本配置ADMIN———————— from django.db import models # Create your models ...
- Django项目:CRM(客户关系管理系统)--73--63PerfectCRM实现CRM讲师下载作业
# teacher_urls.py # ————————62PerfectCRM实现CRM讲师讲课记录———————— from django.conf.urls import url from bp ...
随机推荐
- spring boot 系列之二:spring boot 如何修改默认端口号和contextpath
上一篇文件我们通过一个实例进行了spring boot 入门,我们发现tomcat端口号和上下文(context path)都是默认的, 如果我们对于这两个值有特殊需要的话,需要自己制定的时候怎么办呢 ...
- How to preview html file in our browser at sublime text?
sublime preview html.md open In Browser what should we do if we want to preview html file in our bro ...
- [LeetCode] Replace Words 替换单词
In English, we have a concept called root, which can be followed by some other words to form another ...
- [HAOI 2007]反素数ant
Description 对于任何正整数x,其约数的个数记作g(x).例如g(1)=1.g(6)=4. 如果某个正整数x满足:g(x)>g(i) 0<i<x,则称x为反质数.例如,整数 ...
- [AHOI2005]洗牌
题目描述 为了表彰小联为Samuel星球的探险所做出的贡献,小联被邀请参加Samuel星球近距离载人探险活动. 由于Samuel星球相当遥远,科学家们要在飞船中度过相当长的一段时间,小联提议用扑克牌打 ...
- 矩阵树Matrix-Tree定理与行列式
简单入门一下矩阵树Matrix-Tree定理.(本篇目不涉及矩阵树相关证明) 一些定义与定理 对于一个无向图 G ,它的生成树个数等于其基尔霍夫Kirchhoff矩阵任何一个N-1阶主子式的行列式的绝 ...
- ●CodeForces 480E Parking Lot
题链: http://codeforces.com/problemset/problem/480/E题解: 单调队列,逆向思维 (在线的话应该是分治做,但是好麻烦..) 离线操作,逆向考虑, 最后的状 ...
- [JLOI2015]城池攻占 左偏树
题目描述 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池.这 n 个城池用 1 到 n 的整数表示.除 1 号城池外,城池 i 会受到另一座城池 fi 的管辖,其中 fi &l ...
- ●POJ 2284 That Nice Euler Circuit
题链: http://poj.org/problem?id=2284 题解: 计算几何,平面图的欧拉定理 欧拉定理:设平面图的定点数为v,边数为e,面数为f,则有 v+f-e=2 即 f=e-v+2 ...
- hdu 4578 线段树(标记处理)
Transformation Time Limit: 15000/8000 MS (Java/Others) Memory Limit: 65535/65536 K (Java/Others) ...