Python CRM项目六
自定义Django Admin的action
在Django Admin中,可以通过action来自定义一些操作,其中默认的action的功能是选中多条数据来进行删除操作
我们在king_admin中也可以通过开发类似的功能性组件来实现自定义action
首先在king_admin中添加actions字段
actions = ['delete_selected_objs',] #和django admin一样,添加默认删除选中的多条记录的方法
在views视图中,获取前端页面传来的选中的记录id和action的函数名
#post请求执行action操作 if request.method == 'POST': selected_ids = request.POST.get('selected_ids')#获取选中记录的id action_name = request.POST.get('action')#获取函数名 if selected_ids:
#根据选中记录的id去数据库中获取记录 selected_objs = admin_class.model.objects.filter(id__in=selected_ids.split(',')) else: raise KeyError('没有数据')
#如果在admin_class中找到了该函数,则获取该函数,然后将admin_class,request和查询的记录传递到king_admin.py中的函数 if hasattr(admin_class,action_name): action_func = getattr(admin_class,action_name) request._action = action_name return action_func(admin_class,request,selected_objs)
在king_admin.py中,获取这些参数,第一次调用时候,返回预删除页面,将值回填到预删除页面,当点击确认删除,此时delete_confrim值可获取到,
并且执行删除操作,执行完毕跳转到展示页
def delete_selected_objs(self,request,query_set): app_name = self.model._meta.app_label #获取app的名称 model_name = self.model._meta.model_name #获取表名 selected_ids = ','.join([str(i.id) for i in query_set]) #获取选中记录的id if request.POST.get('delete_confirm') == 'yes':
#当在待删除页面,点击确认删除的时候,delete_confirm才会有值,第一次进入该方法时,这里的值为空 query_set.delete() return redirect('/king_admin//%s/%s/' % (app_name,model_name)) #返回到待删除页面,传递的参数分别是(要删除的记录,admin_class,app名称,表名,选中的id,和要调用的方法)
#主要是为了点击确认删除时候,页面跳转到views中的方法,此时selected_id和action_name的值要回填,否则报错 return render(request,'king_admin/table_delete.html',{'model_obj':query_set, 'admin_class':self, 'app_name':app_name, 'table_name':model_name, 'selected_ids':selected_ids, 'action':request._action})
前端页面
作用: 1.在下拉列表中展示可调用的action
2.checkbox的多条数据删除和数据校验
<div class="row"> <form method="POST" onsubmit="return submitAction(this)">{% csrf_token %} <div class="col-lg-2"> <select name="action" id="action_list" class="form-control" style="margin-top:20px"> <option value="">-----</option> {% for action in admin_class.actions %} <option value="{{ action }}">{% build_action_name admin_class action %}</option> {% endfor %} </select> </div> <div class="col-lg-2"> <button type="submit" class="btn" style="margin-top:20px;margin-left:-10px">执行</button> </div> </form> </div>
<table class="table table-hover"> <thead> <tr> <th><input type="checkbox" onclick="checkAllToggle(this)"></th> {% for column in admin_class.list_display %} {# 动态展示表格中的数据,排序关键字,和筛选条件#} {% build_table_header_column column orderby_key filter_conditions %} {% endfor %} </tr> </thead> <tbody> {# <!--动态展示后端的表格中的数据--!>#} {% for obj in query_sets %} <tr> <td><input tag="obj_check" type="checkbox" value="{{ obj.id }}"/></td> {% bulid_table_row request obj admin_class %} </tr> {% endfor %} </tbody> </table>
js部分
function checkAllToggle(ths){ //复选框全选,反选 if($(ths).prop('checked')){ $("input[tag='obj_check']").prop('checked',true); } else { $("input[tag='obj_check']").prop('checked', false); } } function submitAction(ths){ //后台提交action所要的数据 selected_ids = []; //将复选框选中的值放到列表中 $("input[tag='obj_check']:checked").each(function(){ selected_ids.push($(this).val()); }); //获取action的名字 var select_action = $('#action_list').val(); console.log(select_action) if(selected_ids.length == 0){ alert('没有选择数据'); return; } if(!select_action){ alert('没有选择方法'); return; } //添加已经选择的id,放到隐藏域中,一起提交到后台 var selected_id_ele = "<input name='selected_ids' type='hidden' value='"+selected_ids.toString()+"'/>"; $(ths).append(selected_id_ele); return true; }
预删除页面展示
在预删除页面,加入回填的参数,在点击确认删除时,获取king_admin中传递到前端的值,在把这些值第二次传递给后端的views中,此时views中会第二次调用
king_admin中的action的方法,同时获取到delete_confirm的值,执行删除操作,删除完毕后跳转首页
{% block container %} {% display_obj_related model_obj %} <form method="post">{% csrf_token %} <input type="submit" class="btn btn-danger" value="确认删除"> <input type="hidden" value="yes" name="delete_confirm"> <input type="hidden" value="{{ selected_ids }}" name="selected_ids"> <input type="hidden" value="{{ action }}" name="action"> <a class="btn btn-info" href="{% url 'table_objs' app_name table_name %}">返回</a> </form> {% endblock %}
最后一步,可以通过在action中自定义显示的函数名
class CustomerAdmin(BaseAdmin): list_display = ['qq','name','source','consultant','consult_course','date','status'] list_filters = ['source','consultant','consult_course','status','date'] search_fields = ['qq','name','consultant__name'] list_per_page = 5 ordering = 'id' filter_horizontal = ['tags',]
#继承父类中的action,每个类自定义的action actions = ['delete_selected_objs','test',] def test(self,request,query_set): print('test...') #加上这条属性表示在action下拉框中展示此字段 test.display_name = '测试'
在tags中渲染
@register.simple_tag def build_action_name(admin_class,action): #获取admin_class的action对象 action_func = getattr(admin_class,action)
#如果有display_name就返回display_name的名称,否则就展示action字段 return action_func.display_name if hasattr(action_func,'display_name') else action
前端页面展示
<select name="action" id="action_list" class="form-control" style="margin-top:20px"> <option value="">-----</option> {% for action in admin_class.actions %}
{# <!--自定义标签中去显示下拉框的名称--!>#} <option value="{{ action }}">{% build_action_name admin_class action %}</option> {% endfor %} </select>