Xadmin控件的实现:〇七查询视图五——list视图action功能

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="width: 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="width: 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="width: 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="width: 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="width: 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="width: 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跳转的别的页面上。

通用model的默认action

 注意一下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列表,那么就直接拼到后面,否则就是只有默认的批量删除功能。

posted @ 2020-08-21 11:31  银色的音色  阅读(286)  评论(0编辑  收藏  举报