需求概要:
有个iterm,他有一个属性是类型(只有主和副),iterm是自关联。
有一个需求是这样的,无论是哪个iterm点进来,
如果这个iterm是主: 要展示当前iterm和iterm所有的子iterm
如果这个iterm是副: 要展示其主iterm和主iterm所有的子iterm
代码如下:
current_iterm = self.get_object()
# 先找到主
if current_iterm.version_type == const.VERSION_TYPE_SUB:
main_version_iterm = iterms.objects.get(pk=current_iterm.parent_id)
elif current_iterm.version_type == const.VERSION_TYPE_MAIN:
main_version_iterm = current_iterm
else: # 找不到iterm
raise SHException(errors.ERR_INVALID_VALUE, 'Invalid uuid.')
# 获取主版本、副版本的queryset
main_version_iterm_qs = iterms.objects.filter(pk=main_version_iterm.uuid)
sub_version_iterms_qs = iterms.objects.filter(parent_id=main_version_iterm.uuid).all()
现在 我们有了两个queryset,一个main_version_iterm_qs, 一个sub_version_iterm_qs
首先我们可以使用 `|` 管道符 来合并两个queryset。
data = main_version_iterm_qs | sub_version_iterms_qs
# 使用list源码,将详情接口返回list
page = self.paginate_queryset(data)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(data, many=True)
但是,我们使用分页serializer后发现顺序变了。
这样不符合将main放在前面的需求,pass。
然后我们考虑使用chain,就是itertools里面的链,将可迭代对象迭代组合成一个列表
data = chain(main_version_iterm_qs, sub_version_iterms_qs)
但是呢,这样将data传入serializer里面会提示:
object of type 'itertools.chain' has no len()
没有len方法。
所以:重新使用列表生成式重新赋值data,这样就可以了。
# 将主版本和副版本拼一起,主版本永远在最前面
data = chain(main_version_iterm_qs, sub_version_iterms_qs)
data = [iterm for iterm in data]
# 使用list源码,将详情接口返回list
page = self.paginate_queryset(data)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(data, many=True)
PS: 这样是将所有的数据库数据拿到内存中再分页,消耗还是比较大,求有更好的建议!
既然可以用chain,当然也有更原始的方法。
data_list = []
data_list.extend(main_version_work_qs)
data_list.extend(sub_version_work_qs)
然后使用序列化 分页就可以完成了。
PS: 这种方法是将所有的数据库数据拿到内存中再分页,消耗还是比较大,求有更好的建议!