实现目标
在数据列表页面,用户选中checkbox后再选中批量操作的动作后点击执行,完成操作
实现思路
- 前端页面给每行数据添加checkbox选项
- 前端页面添加下拉菜单,因为以后拓展需求大了,批量操作动作比较多,排列在页面上不好看,利用select和option选项比较好
- 给select设置name属性,给option设置value属性和文本属性
- 给checkbox设置value属性和name属性
- 后台给出接口,让应用选择批量操作的动作
- 后台编写相对应动作的处理函数
- 通过POST请求拿到option的value属性和checkbox的value属性
- 拓展函数参数
具体实现与知识点
给checkbox设置value属性和name属性
我们之前利用display_xx函数实现了在页面上定制添加列,所以我们现在需要给每一行数据添加checkbox选项也使用这个方法,需要注意的地方是,我们在后面进行批量操作的时候,需要拿到每一行数据对应的ID后才能进行操作,进行POST请求的时应该把checkbox选中的数据的ID传递到后台。
在编写checkbox时给他设置一个value值,还需要设置一个name,以方便在POST数据中拿到value值
def display_checkbox(self, obj=None, is_header=None): """ 为每行数据显示checkbox选项 :param obj: :param is_header: :return: """ if is_header: return '选项' # 表头 return mark_safe('<input type="checkbox" value="%s" name="check">' % obj.pk) #value值设置为每次循环对象的.pk,实际就是每一个数据的ID值
在应用层定制的list_display列表中将 display_checkbox函数添加到列表第一个数据即实现前端添加checkbox选项
前端中,批量操作的下拉菜单根据用户定制而显示
按照我们之前的做法,在应用层面设置一个批量操作列表action_list,将批量操作函数放入列表,把action_list传入前端中,在前端中循环action_list,得到每个函数对象。但是在前端中想要取到我们定制的函数中文名称该怎么办呢?
函数的text属性
我们在后端可以给函数设置一个text属性,在前端中直接取该函数的text属性
后端视图函数.py
def action_multi_delete(self, requset): """ 批量处理删除的函数 :param requset: :return: """ pass action_multi_delete.text = '批量删除' # 对批量操作的函数设置一个text属性,用于前端显示中文
前端.html
<select class="form-control" name="action" id=""> <option>请选择操作</option> {% for func in action_list %} # 循环后台传入的action_list列表,列表中是每个批量操作的函数 <option>{{ func.text }}</option> {% endfor %} </select>
然而! 我们按照这个思路却无法实现。
我们看到,在前端中没有读取到函数.text值, 但是我们发现,在action_list中有两个函数,前端中的select下来款中也是两个下拉选项。
def changelist_view(self, request): """ 用户列表函数 :return: """ # 1 处理批量操作 action_list = self.get_action_list() for item in action_list: print('测试:', item.text)
输出:
测试: 批量删除
测试: 批量初始化
我们发现,在前端中虽然没有显示中文内容,但是数量是和我们的action_list列表中函数个数相对于的。
这是为什么呢?
因为在前端{{ }}语法中传入函数,默认是不用加括号就执行函数。所以并不会按照我们想要的去获取函数的text属性
那我们应该如何在前端页面中显示后端传入函数的text属性呢?
我们需要对action_list数据进行调整,调整数据结构。
这里的思路是利用字典的key,value来处理数据格式, 我们可以设计成 action_dict = {'函数名': '函数.text'}, 这样我们不但得到了 函数.text,我们还拿到了函数名。 这个东西非常有用。
但是,我们如何拿到函数的字符串形式的函数名呢?
利用函数.__name__属性
def my_func_name(): pass print(my_func_name.__name__) # 函数的__name__属性会返回函数的函数名
函数的__name___会得到该函数的字符串形式的函数名
这样我们在action_dict中得到的数据格式就是: {'test_func_name': '测试函数文本'} ,在前端中对action_dict进行循环,文本内容就为函数的text属性。
设置option的value属性
我们根据获取用户选择的option可以拿到用户想要执行的函数,那我们的value值如果直接设置成函数名,在后端中就可以根据函数名找到对应的函数去执行。
所以在action_dict数据设计上选择的模式是非常巧妙的,即解决了显示文本,还一次性把需要执行的函数名称也传到后端中去了。
前端中对整个表格进行form表单的POST数据发送,在后端中通过获取POST请求中select的name值,可以拿到select下面option的value值,自然就拿到批量操作动作对应的函数名
根据函数名去执行相对于的函数
利用反射!
拿到字符串的函数名后通过反射可以得到函数对象,并且执行。
def changelist_view(self, request): """ 用户列表函数 :return: """ # 1 处理批量操作 action_list = self.get_action_list() action_dict = {func.__name__: func.text for func in action_list} if request.method == 'POST': action_func_name = request.POST.get('action') # 获取select的name属性可以得到option的value值 if action_func_name or action_func_name in action_dict: getattr(self, action_func_name)(request)
知识点总结: 主要利用了对action_dict格式的设计,实现了文本定制和传递函数名称, 后端中利用反射在拿到名称的情况下获取到函数对象并执行
重要知识点: 格式设计、 反射