之前主要介紹了前端頁面list_fiter功能的顯示,但是list_display功能的展示并沒有過多介紹,這里介紹一下是如何實現(xiàn)的。
可以看到凡是藍線圈起來的都是通過字段名反射一個個取出來的,紅線的是通過函數(shù)來構(gòu)造的,這也就說明,list_display中單是字段名是不夠的,還需要加入一些數(shù)據(jù)庫中沒有的東西。這里可以加入字段以及構(gòu)建的函數(shù)。
list_display = [BaseStark.display_checkbox,'id','name','contact','status','source','referral_from','product','consultant','consultant_date',display_follow,display_order]
那么怎么對它進行處理呢?
表頭處理:
def header_list(self,request,*args,**kwargs): list_display = self.get_list_display() if list_display: for field in list_display: if isinstance(field, FunctionType): header_name = field(self, row=None, header_body=False, *args, **kwargs) # 加后面的編輯框 else: header_name = self.model_class._meta.get_field(field).verbose_name # 獲取對應(yīng)字段的verbose_name yield header_name else: yield self.model_class._meta.model_name # 如果list_display中沒有值顯示表名
表內(nèi)容處理:
def body_list(self,request,queryset,*args,**kwargs): list_display = self.get_list_display() for row in queryset: row_list = [] # 注意必須放在這個循環(huán)下面 if not list_display: # list_display中沒有值 row_list.append(row) yield row_list continue for field_or_func in list_display: # list_display中有值 if isinstance(field_or_func, FunctionType): val = field_or_func(self, row=row, header_body=True, *args, **kwargs) elif field_or_func in self.list_editable: val = self.render_editable_value(row,field_or_func) else: field_obj = self.model_class._meta.get_field(field_or_func) # 獲取字段對象 if field_obj.choices: val = getattr(row, "get_%s_display" % field_or_func)() elif isinstance(field_obj, ManyToManyField): queryset = getattr(row, field_or_func).all() # ManyToManyField反射需要加all() val_list = [] for obj in queryset: val_list.append(str(obj)) val = '、'.join(val_list) else: val = getattr(row, field_or_func) # ForeignKey字段反射,ManyToManyField會出現(xiàn)問題 if not val: val = '' row_list.append(val) yield row_list
在這里對list_display中的字段進行了判斷,普通字段、Foreignkey、ManyToMany、函數(shù)分別做不同的處理。另外在循環(huán)list_display的過程中引入list_editable的功能,那么它又是怎么完成的呢?
其實就是將ForeignKey以及choice類型的字段變成select標(biāo)簽,每一個option的value值就是它們自身的id,普通字段就給它變成input框就可以了。
def render_editable_value(self,row,field_or_func): field_obj = self.model_class._meta.get_field(field_or_func) # 獲取字段對象 if hasattr(row,field_or_func): if field_obj.get_internal_type() == "ForeignKey": field_val=getattr(row,"%s_id"%(field_obj.name)) else: field_val=getattr(row,field_or_func) else: field_val='' if not field_obj.choices and field_obj.get_internal_type() != "ForeignKey" : if field_obj.get_internal_type() == "DateTimeField": val = '''<input data-tag='editable' class='form-control' type='text' name='%s' value='%s' date_time='datetimepicker'>''' % (field_obj.name, getattr(row, field_obj.name) or '') else: val = '''<input data-tag='editable' class='form-control' type='text' name='%s' value='%s' >''' %(field_obj.name,getattr(row,field_obj.name) or '') else: val = '''<select data-tag='editable' class='form-control' name='%s' >''' % field_obj.name for option in field_obj.get_choices(): if option[0] == field_val: selected_attr = "selected" else: selected_attr = '' val = '''<option value='%s' %s >%s</option>'''% (option[0],selected_attr,option[1]) return mark_safe(val)
這里有一個注意的地方,字段對象如果是choice或者foreignker類型都可以使用field_obj.get_choice(),取到的就是一個個元組組成的列表,前臺通過list_editable修改完成后通過ajax進行數(shù)據(jù)發(fā)送。只發(fā)送那些改動過的數(shù)據(jù)。
<table class="table table-hover table-bordered table_content"> <thead > <tr> {% for row in cl.header_list %} <th class="table_content">{{ row }}</th> {% endfor %} </tr> </thead> <tbody id="model_table_data"> {% for row_list in cl.body_list %} <tr> {% for val in row_list %} <td>{{ val }}</td> {% endfor %} </tr> {% endfor %} </tbody> </table>
function SendData() { $('#submit').click(function () { var $action_val=$('#action').val(); var form_data = [{"action":$action_val}]; $("#model_table_data tr").each(function () { var obj_id = $(this).children().first().find("input").val(); if (obj_id){ var row_data = {}; $(this).find("[data-tag='editable']").each(function () { var val=$(this).val(); row_data[$(this).attr("name")] = $(this).val(); });//end find each row_data['id'] = obj_id; form_data.push(row_data); } });//end each {#alert(JSON.stringify(form_data));#} $.ajax({ headers:{'X-CSRFToken':$.cookie('csrftoken')}, type:'POST', dataType:"JSON", contentType:"application/json", data:JSON.stringify(form_data), success:function (arg) { } }) }) }
這樣就將需要更改的數(shù)據(jù)發(fā)送到后臺了,但是是否注意,我發(fā)送ajax數(shù)據(jù)時,另外還發(fā)送了一個action的數(shù)據(jù),這又是干什么呢?實際上在頁面上我有action_list這么一個功能,在這里,將action_list選項的功能變成既可以發(fā)送form表單數(shù)據(jù),也可以進行ajax發(fā)送,然后在后臺根據(jù)發(fā)送過來的函數(shù)名稱進行反射處理即可。
{% if cl.action_list %} <div class="form-group" style="padding: 5px 0"> <select id="action" name="action" class="form-control" style="min-width: 200px;"> <option value="">請選擇相應(yīng)的功能</option> {% for item in cl.action_list %} <option value="{{ item.name }}">{{ item.attr_dict.text }}</option> </select> {% if item.attr_dict.id %} <input type="button" value="執(zhí)行" id="{{ item.attr_dict.id }}" class="btn btn-primary"> {% else %} <input type="submit" value="執(zhí)行" class="btn btn-primary"> {% endif %} {% endfor %} </div> {% endif %}
后臺處理list_editable功能的函數(shù)
def changelist_view(self, request,*args,**kwargs): """ 處理顯示數(shù)據(jù)的頁面 :param request: :return: """ if request.method == 'POST': editable_data=str(request.body,encoding='utf-8') if editable_data: editable_data=json.loads(editable_data) action_name=editable_data[0].get('action') #ajax請求 action_name = request.POST.get('action') or action_name # 普通form表單請求 if action_name: if action_name not in self.get_action_dict(): # 防止前端客戶刻意修改代碼,進行驗證 return HttpResponse('非法請求!') response = getattr(self, action_name)(request,*args,**kwargs) # 反射執(zhí)行函數(shù) action_name就是函數(shù)名稱 if response: return response # 返回什么結(jié)果就是什么
執(zhí)行反射的函數(shù)
def muti_editable_save(self, request,*args,**kwargs): """ ajax實現(xiàn)list_editble保存,通過判斷是否有id屬性 muti_editable_save.attr_dict = {'text':'批量保存','id':'submit'} :param request: :param args: :param kwargs: :return: """ editable_data = str(request.body, encoding='utf-8') if editable_data: editable_data = json.loads(editable_data) ## for list editable del editable_data[0] #print('反射',editable_data) # [{'confirm_user': '7', 'confirm_date': '1899-12-13 09:50:00 00:00', 'id': '2'}] for row_data in editable_data: obj_id = row_data.get('id') if obj_id: #print("editable data", row_data, list(row_data.keys()))#['id', 'confirm_user', 'confirm_date'] obj = self.model_class.objects.get(id=obj_id) model_form = self.create_list_editable_model_form(list(row_data.keys())) form_obj = model_form(instance=obj, data=row_data) if form_obj.is_valid(): form_obj.save()muti_editable_save.attr_dict = {'text':'批量保存','id':'submit'}
這樣很容易就實現(xiàn)了list_editable的保存,而且以后如果想通過action_list各個功能的話,指的,可以選擇ajax發(fā)送數(shù)據(jù),或者表單發(fā)送,只需要在后臺中給對應(yīng)的處理函數(shù)賦值相應(yīng)的id屬性就可以了,值得注意的是,如果使用ajax功能的,就必須加上display_checkbox(),因為取id的時候就是通過checkbox中來獲取的,這就是列表頁面的主要功能了。
?
來源:http://www.icode9.com/content-4-204001.html