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的值所有報錯),下一章解決

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM