Django - Xadmin (四) Filter
Filter 功能描述
与 admin 组件中 Filter 功能类似,在展示页面右侧放置一列标签,通过点击这些标签来筛选出该标签相关的数据。
比如, Filter 中有关于出版社分类的标签,点击相关出版社的标签会将关于该出版社的书籍数据列出来。
实现过程实际上就是 a 标签加上后台数据筛选和标签渲染。
后台处理
后台处理主要分为两块, ModelXadmin 类中的处理和 ShowList 类中的处理。
ModelXadmin 类
首先,在 ModelXadmin 类中加上 Filter 字段。 filter_fields = []
Filter 功能实际上就是对数据的筛选,所以创建个函数用于根据前端传来的数据获取筛选条件。筛选条件是 GET 传来的参数,用 Q 函数类解决,因为筛选可以赋予多个条件,所以这之间是 “且” 的关系。
def get_filter_condition(self, request):
filter_condition = Q()
for filter_field, val in request.GET.items():
if filter_field in self.filter_fields:
filter_condition.children.append((filter_field, val))
return filter_condition
获取了筛选条件就可直接进行筛选,而且 filter 函数可以直接过滤多个条件。
# 获取filter的Q对象
filter_connection = self.get_filter_condition(request)
# 筛选数据
data_list = self.model.objects.filter(search_connection).filter(filter_connection)
ShowList 类
Filter 功能实现的最主要部分还是在 ShowList 类中,在此类中将需要的 a 标签构建并进行渲染。
遍历 filter_fields ,获取每个字段在模型表中对应的字段对象,根据字段类型不同以不同的方式获取字段的数据列表。
处理数据标签:
先判断该数据所属的字段对象是否为外键关联或者是多对多关联,如果是,获取其字段对象的主键和描述,并将主键作为传值参数;否则,将其描述作为传值参数。获取主键和描述的意义在于判断当前数据标签是否已被点击,被点击的标签返回的是带有激活样式的 a 标签。
同时,需要增加 “全部” 标签,对字段本身进行筛选。
def get_filter_linktags(self):
link_dic = {}
for filter_field in self.config.filter_fields:
params = copy.deepcopy(self.request.GET)
cid = self.request.GET.get(filter_field, 0)
filter_field_obj = self.config.model._meta.get_field(filter_field)
# 根据字段不同类型获取该字段的数据
if isinstance(filter_field_obj, ForeignKey) or isinstance(filter_field_obj, ManyToManyField):
data_list = filter_field_obj.rel.to.objects.all()
else:
data_list = self.config.model.objects.all().values("pk", filter_field)
temp = []
# 处理 全部标签
if params.get(filter_field):
del params[filter_field]
temp.append("<a href='?%s'>全部</a>" % params.urlencode())
else:
temp.append("<a class='active' href='#'>全部</a>")
# 处理数据标签
for obj in data_list:
if isinstance(filter_field_obj, ForeignKey) or isinstance(filter_field_obj, ManyToManyField):
pk = obj.pk
text = str(obj)
params[filter_field] = pk
else:
pk = obj.get("pk")
text = obj.get(filter_field)
params[filter_field] = text
_url = params.urlencode()
if cid == str(pk) or cid==text:
link_tag = "<a class='active' href='?%s'>%s</a>" % (_url, text)
else:
link_tag = "<a href='?%s'>%s</a>" % (_url, text)
temp.append(link_tag)
link_dic[filter_field] = temp
return link_dic
前端处理
前端的处理以简单为准则。这次只需要对后台传来的有关数据标签的数据结构进行循环遍历且将相应字段放好即可。
<div class="col-md-3">
<div class="filter">
<h4>Filter</h4>
{% for filter_field, linktags in showlist.get_filter_linktags.items %}
<div class="well">
<p>BY {{ filter_field.upper }}</p>
{% for link in linktags %}
<p>{{ link|safe }}</p>
{% endfor %}
</div>
{% endfor %}
</div>
</div>
完整代码:Filter功能 GitHub 地址