涉及知识点:
1. 迭代器 2. 根据点击的单选框设计URL参数 3. 根据URL参数过滤数据并展示
首先,我们设计一个迭代器,迭代器可以返回a标签单选框,将这些a标签单选框传给前端页面,前端页面循环根据迭代器生成的迭代器对象,即可显示出a标签单选框。在渲染页面的时候,我们从数据库中拿到要展示的choice类型字段的choice数据,构造成下面这种形式。将这个数据传递给前端,CheckFilter即为一个迭代器。
filter_list = [ {'title': "问题类型", 'filter': CheckFilter('issues_type', project_issue_type, request)}, {'title': "状态", 'filter': CheckFilter('status', models.Issues.status_choices, request)}, {'title': "优先级", 'filter': CheckFilter('priority', models.Issues.priority_choices, request)}, ]
在迭代器中,我们做这么几件事情:首先我们将要使用的数据初始化一下,data_list是数据库中的choice类型字段,是元组里面套元组的格式,然后定义__iter__方法,在这个方法里面,我们首先循环我们拿到的data_list,分别定义key和text,然后得到当前请求的URL中的参数,定义为value_list,使用request.GET.getlist()方法;每次循环的时候,判断key是否在value_list中,如果在就将value_list中的key值移除,如果不在就将这次循环的key值添加到value_list中。每次循环在构造好了value_list数据之后,我们通过request.GET获取URL中的参数和参数值,得到的是QueryDict类型数据,将这个QueryDict数据通过urldecode()方法解析成路由参数的形式,再通过request.path_info获取主路由,将参数和路由在一起拼接成一个完整路由。接着我们够造a标签单选框,里面的路由即为构造好的路由。如果要为点击的单选框添加checked形式怎么办?我们在判断key是否在value_list中去够造每次循环需要的value_list的时候,我们可以这样定义:如果单次循环的key在value_list中,那么我们定义一个check="checked",如果不在那么check=“”,然后再够造a标签的时候将check添加到a标签中,通过mark_safe的方式生成a标签,然后yield这个a标签。在后端利用这个迭代器生成一个迭代器对象,在前端利用这个迭代器对象进行渲染a标签单选框
代码如下:
class CheckFilter(object): def __init__(self, name, data_list, request): self.name = name self.data_list = data_list self.request = request def __iter__(self): for item in self.data_list: key = str(item[0]) text = item[1] ck = "" # 如果当前用户请求的URL中参数名和当前循环key相等 value_list = self.request.GET.getlist(self.name) # ['2', '3', '4'] #print(value_list) #如果url中携带的参数值在数据库中,就移除,不在就添加 if key in value_list: ck = 'checked' value_list.remove(key) else: value_list.append(key) #print(key,text,value_list) # 为自己生成URL # 在当前URL的基础上去增加一项 # status=1&age=19 from django.http import QueryDict query_dict = self.request.GET.copy() #<QueryDict: {'status': ['2', '3', '4']}> query_dict._mutable = True query_dict.setlist(self.name, value_list) if 'page' in query_dict: query_dict.pop('page') param_url = query_dict.urlencode() #print(param_url) #print("*" * 10) if param_url: url = "{}?{}".format(self.request.path_info, param_url) # status=1&status=2&status=3&xx=1 else: url = self.request.path_info tpl = '<a class="cell" href="{url}"><input type="checkbox" {ck} /><label>{text}</label></a>' html = tpl.format(url=url, ck=ck, text=text) yield mark_safe(html)
这里有一点我个人认为比较难理解的地方,就是在够造value_list的时候的方法。逻辑是这样的:第一次我们进入的页面上的URL没有任何参数,每一个a标签单选框都是自己本身的路由,每次在循环够造新的value_list的时候,从URL获取的value_list是空,所以我们每次都将循环的key添加到value_list中,通过这个新生成的value_list创建a标签的时候就只有一个参数。当我们点击了一个a标签,页面刷新,我们访问的URL中有一个参数,我们再进行循环,假设第一次循环的key在从URL获取的value_list中,那么我们将value_list中的key值移除,此次循环生成的a标签的路由就是主路由,并且加上了checked属性,第二次循环的时候,此次的key不在从URL获取的value_list中,我们将这次的key添加到value_list中,生成新的value_list,利用这个新的value_list生成的a标签中有两个参数,当我们点击这个a标签单选框的时候,我们访问的URL就有两个参数,接下来的循环一样,剩余的每个key对应的a标签都有两个参数。当我们再点击一个新的单选框的时候,即有两个单选框被选中,那么我们点击访问的URL中有两个参数,我们第一次循环的key在从URL获取的value_list中,将其移除,此时value_list中只有一个参数,被选中的单选框生成的a标签的路由中只有一个参数,参数值是另一个被点击的单选框对应的参数,当我们在页面刷新之后再点击这个单选框,这个单选框不被选中,只有一个单选框被选中,所以只有一个参数。而此时另外的未被选择的单选框对应的参数有三个,因为在循环生成a标签的时候,key不在从URL获得的value_list中,我们进行追加,三个参数分别是已经点击的两个单选框参数和本身。点击多个单选框的时候,逻辑也是一样。每次点击单选框之后,每个单选框对应的a标签的URL参数都不一样。
如何根据URL参数来过滤数据并展示呢?我们需要根据数据库中的字段定义出name = {‘字段名__in’:[ ]} 的字典,[ ]是choice类型字段的所对应的数字,然后在通过orm筛选数据得时候通过.filter(name) 的方式来筛选出需要的数据。示例代码如下:
def issues(request, project_id): if request.method == 'GET': # 根据URL做筛选,筛选条件(根据用户通过GET传过来的参数实现) allow_filter_name = ['issues_type', 'status', 'priority', 'assign', 'attention'] condition = {} for name in allow_filter_name: params_list = request.GET.getlist(name) if not params_list: continue condition['{}__in'.format(name)] = params_list """ condition = {'issues_type__in':[1,2],'status__in':[1,2,3]} """ # 根据URL参数过滤数据,再分页展示数据 queryset = models.Issues.objects.filter(project_id=project_id).filter(**condition) ......