第八章, 只读字段处理和 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 的实现 https://github.com/derek-zhang123/PerfectCRM
来源: https://www.cnblogs.com/derek1184405959/p/8976851.html