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

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

  • 相关阅读:
    Delphi中Chrome Chromium、Cef3学习笔记(五)
    java ->IO流_File类
    java ->递归
    java-> 分包分层
    java ->JDBC
    java -> 异常类与自定义异常
    java ->斗地主洗牌
    java -> map接口
    java ->Set接口
    java -> List接口
  • 原文地址:https://www.cnblogs.com/yinsedeyinse/p/13526974.html
Copyright © 2020-2023  润新知