action功能主要用于批量的操作,主要是结合select标签一起使用,admin控件在不设置的时候默认包含了一个删除所有已选择的对象。
我们还可以自定义action,就是在自定义的配置类里写一个函数,然后把这个函数名添加到列表里。
我们主要来看一下当我们点击了go按钮以后发生了什么事情:
两组键值对
检查一下点击go按钮以后,其实是发送了一个POST请求的过程,提交请求的时候带了两组键值对,一个是action自己下拉菜单里的值,还有一组就是checkbox对应的值。而先选函数或者先选checkbox是没有影响的,只是最后点击go按钮的时候进行submit提交表单的时候才获取最终的值。
下拉列表的构造
下拉列表里的内容要怎么获取呢?在配置累里有个列表,actions = [],默认情况是没有值得
在自定义配置类的时候,可以自定义一个函数,然后怎么把这个函数的名称显示在下拉列表里呢?
1 class BookConf(ConfXadmin): 2 list_display = deepcopy(ConfXadmin.list_display) 3 list_display.append('price',) 4 search_fields = ['title','price'] 5 6 def patch_init(self,queryset): 7 print(queryset) 8 9 patch_init.desc = '测试用action' 10 actions = [patch_init]
注意最后一行的代码,我们是把函数对象放在列表里的,然后在定义一个函数
1 def get_actions_name(self): 2 temp = [] 3 for action in self.actions: 4 temp.append(action.__name__) 5 6 return temp
直接把函数名放在一个列表里返回就可以了,然后我们在模板中调用这个函数
<select name="action" id="" style=" 200px; padding: 5px,8px;display: inline-block;"> <option value="">--------------</option> {%for action in view_obj.conf_obj.get_actions_name%} <option value="">{{action}}</option> {%endfor%} </select>
这样用一个for循环就能生成需要的列表里
按自定义要求显示函数名
admin中是可以通过一个参数short_description来指定显示在下拉列表里的函数的函数名,那么我们怎么实现这个功能呢?
1 def get_actions_desc(self): 2 temp = [] 3 for action in self.actions: 4 temp.append({'name':action.__name__,'desc':action.desc}) 5 return temp
我们就以一个字典的形式来保存函数的名称和描述值,然后结合前端的for循环就能拿到所需要的列表
但是还有一点问题,如果没有设置desc的时候在前端里是拿不到数据的,这时候就要用到反射,
1 def get_actions_desc(self): 2 temp = [] 3 for action in self.actions: 4 if not hasattr(action,'desc'): 5 action.desc = action.__name__ 6 print(1111111111111111111111) 7 temp.append({'name':action.__name__,'desc':action.desc}) 8 return temp
然后在模板里这样做
<select name="action" id="" style=" 200px; padding: 5px,8px;display: inline-block;"> <option value="">--------------</option> {%for action in view_obj.conf_obj.get_actions_desc%} <option value="{{action.name}}">{{action.desc}}</option> {%endfor%} </select>
action.desc是action的描述,当有desc点时候就显示为我们指定的字符串,否则就显示为函数名。而action.name直接就是函数名,我们可以拿到这个函数名然后再后台里直接通过反射运行函数。
获取选中的数据行
在上面的流程中我们已经拿到了第一个键值对——可以执行选中的函数。下面就要看看怎么拿到第二个键值对——获取选中的数据行了
在生成checkbox的时候,我们应该给他指定一个name值,还有一个value值,那么在表单在POST的过程中我们就可以通过这个name拿到一个列表,里面是选中的对象的value。为了便于后期的数据库操作,我们可以吧这个value设置的和主键id一样
1 def select(self,obj=None,get_title=False): 2 if not get_title: 3 return mark_safe("<input type='checkbox' name='selected_pk' value='%s'>"%obj.pk) 4 else: 5 return mark_safe("<input type='checkbox' class = 'selected'>全选")
上面是我们视图中生成checkbox的函数,注意第3行里修改以后的部分,加上了name和value
非常重要的一点
我们拿到这个选中id组成的列表是通过form标签构成的表单,那么一定要注意这个form的闭合标签的位置,
<form action="" method="POST"> {%csrf_token%} <select name="action" id="" style=" 200px; padding: 5px,8px;display: inline-block;"> <option value="">--------------</option> {%for action in view_obj.conf_obj.get_actions_desc%} <option value="{{action.name}}">{{action.desc}}</option> {%endfor%} </select> <button type="submit">GO</button> <table class="table table-bordered table-striped"> <thead> </thead> <tbody> </tbody> </table> </form>
由于selectbox是包含在table里的,必须把form的闭合标签放在table后面。这个效果不太好试,图就不截了。
POST.get和POST.getlist
注意request.POST.get()方法只能拿到列表中的最后一个元素,这里也是要注意的点。因为选中的对象以后通过POST里的Querydict中的列表存在的
<QueryDict: {'csrfmiddlewaretoken': ['klNkPOTx4AHP7usgLxBO6zjinSpaOzXmAUgTrXy5qneHQn1vSEkDsX5Zx2j2BHOQ'], 'action': [''], 'selected_pk': ['4', '5']}>
所以我们必须用getlist方法才能拿到所有的id值。
后台程序的处理
------------恢复内容开始------------
action功能主要用于批量的操作,主要是结合select标签一起使用,admin控件在不设置的时候默认包含了一个删除所有已选择的对象。
我们还可以自定义action,就是在自定义的配置类里写一个函数,然后把这个函数名添加到列表里。
我们主要来看一下当我们点击了go按钮以后发生了什么事情:
两组键值对
检查一下点击go按钮以后,其实是发送了一个POST请求的过程,提交请求的时候带了两组键值对,一个是action自己下拉菜单里的值,还有一组就是checkbox对应的值。而先选函数或者先选checkbox是没有影响的,只是最后点击go按钮的时候进行submit提交表单的时候才获取最终的值。
下拉列表的构造
下拉列表里的内容要怎么获取呢?在配置累里有个列表,actions = [],默认情况是没有值得
在自定义配置类的时候,可以自定义一个函数,然后怎么把这个函数的名称显示在下拉列表里呢?
1 class BookConf(ConfXadmin): 2 list_display = deepcopy(ConfXadmin.list_display) 3 list_display.append('price',) 4 search_fields = ['title','price'] 5 6 def patch_init(self,queryset): 7 print(queryset) 8 9 patch_init.desc = '测试用action' 10 actions = [patch_init]
注意最后一行的代码,我们是把函数对象放在列表里的,然后在定义一个函数
1 def get_actions_name(self): 2 temp = [] 3 for action in self.actions: 4 temp.append(action.__name__) 5 6 return temp
直接把函数名放在一个列表里返回就可以了,然后我们在模板中调用这个函数
<select name="action" id="" style=" 200px; padding: 5px,8px;display: inline-block;"> <option value="">--------------</option> {%for action in view_obj.conf_obj.get_actions_name%} <option value="">{{action}}</option> {%endfor%} </select>
这样用一个for循环就能生成需要的列表里
按自定义要求显示函数名
admin中是可以通过一个参数short_description来指定显示在下拉列表里的函数的函数名,那么我们怎么实现这个功能呢?
1 def get_actions_desc(self): 2 temp = [] 3 for action in self.actions: 4 temp.append({'name':action.__name__,'desc':action.desc}) 5 return temp
我们就以一个字典的形式来保存函数的名称和描述值,然后结合前端的for循环就能拿到所需要的列表
但是还有一点问题,如果没有设置desc的时候在前端里是拿不到数据的,这时候就要用到反射,
1 def get_actions_desc(self): 2 temp = [] 3 for action in self.actions: 4 if not hasattr(action,'desc'): 5 action.desc = action.__name__ 6 7 temp.append({'name':action.__name__,'desc':action.desc}) 8 return temp
然后在模板里这样做
<select name="action" id="" style=" 200px; padding: 5px,8px;display: inline-block;"> <option value="">--------------</option> {%for action in view_obj.conf_obj.get_actions_desc%} <option value="{{action.name}}">{{action.desc}}</option> {%endfor%} </select>
action.desc是action的描述,当有desc点时候就显示为我们指定的字符串,否则就显示为函数名。而action.name直接就是函数名,我们可以拿到这个函数名然后再后台里直接通过反射运行函数。
获取选中的数据行
在上面的流程中我们已经拿到了第一个键值对——可以执行选中的函数。下面就要看看怎么拿到第二个键值对——获取选中的数据行了
在生成checkbox的时候,我们应该给他指定一个name值,还有一个value值,那么在表单在POST的过程中我们就可以通过这个name拿到一个列表,里面是选中的对象的value。为了便于后期的数据库操作,我们可以吧这个value设置的和主键id一样
1 def select(self,obj=None,get_title=False): 2 if not get_title: 3 return mark_safe("<input type='checkbox' name='selected_pk' value='%s'>"%obj.pk) 4 else: 5 return mark_safe("<input type='checkbox' class = 'selected'>全选")
上面是我们视图中生成checkbox的函数,注意第3行里修改以后的部分,加上了name和value
非常重要的一点
我们拿到这个选中id组成的列表是通过form标签构成的表单,那么一定要注意这个form的闭合标签的位置,
<form action="" method="POST"> {%csrf_token%} <select name="action" id="" style=" 200px; padding: 5px,8px;display: inline-block;"> <option value="">--------------</option> {%for action in view_obj.conf_obj.get_actions_desc%} <option value="{{action.name}}">{{action.desc}}</option> {%endfor%} </select> <button type="submit">GO</button> <table class="table table-bordered table-striped"> <thead> </thead> <tbody> </tbody> </table> </form>
由于selectbox是包含在table里的,必须把form的闭合标签放在table后面。这个效果不太好试,图就不截了。
POST.get和POST.getlist
注意request.POST.get()方法只能拿到列表中的最后一个元素,这里也是要注意的点。因为选中的对象以后通过POST里的Querydict中的列表存在的
<QueryDict: {'csrfmiddlewaretoken': ['klNkPOTx4AHP7usgLxBO6zjinSpaOzXmAUgTrXy5qneHQn1vSEkDsX5Zx2j2BHOQ'], 'action': [''], 'selected_pk': ['4', '5']}>
所以我们必须用getlist方法才能拿到所有的id值。在拿到了selected_pk以后,我们就可以直接通过filter索引出需要处理的对象交给后台处理。
后台程序的处理
这个时候我们就拿到了需要的两个键值对——批量处理的对象id和要用的函数。这里吧list视图里的POST的部分放出来,其他
1 def list_view(self,request): 2 if request.method == 'POST': 3 action_str = request.POST.get('action') 4 selected_id = request.POST.getlist('selected_pk') 5 6 filter_data = self.model.objects.filter(pk__in = selected_id) 7 8 if hasattr(self,action_str): 9 action = getattr(self,action_str) 10 ret = action(filter_data)
这里就是用了一个反射的方法,我们从POST里get到底acction是一个字符串,要通过字符串去执行函数的话当然是用hasattr和getattr了!我们加上了一个判断,其实用处也不大就是防止出错。
最后一行的ret是因为如果有些自定义的action函数里是可以加上带response的返回值的,后面可以通过加上return ret跳转的别的页面上。
注意一下admin控件里,所有注册的table都有一个通用的action删除所有选中对象。这时候要怎么处理呢?
思路就是和获取显示字段列表一样,在Confxadmin类里添加一个函数
1 def get_actions_list(self): 2 temp = [] 3 temp.append(ConfXadmin.remove_select_obj) 4 temp.extend(self.actions) 5 return temp 6 7 def get_actions_desc(self): 8 temp = [] 9 for action in self.get_actions_list(): 10 if not hasattr(action,'desc'): 11 action.desc = action.__name__ 12 temp.append({'name':action.__name__,'desc':action.desc}) 13 return temp
如果在自定义里有actions列表,那么就直接拼到后面,否则就是只有默认的批量删除功能。