# -*- coding: utf-8 -*- # from itertools import chain from .utils import lazyproperty class Stack(list): def is_empty(self): return len(self) == 0 @property def top(self): if self.is_empty(): return None return self[-1] @property def bottom(self): if self.is_empty(): return None return self[0] def size(self): return len(self) def push(self, item): self.append(item) class QuerySetChain: def __init__(self, querysets): self.querysets = querysets @lazyproperty def querysets_counts(self): counts = [s.count() for s in self.querysets] return counts def count(self): return self.total_count @lazyproperty def total_count(self): return sum(self.querysets_counts) def __iter__(self): self._chain = chain(*self.querysets) return self def __next__(self): return next(self._chain) def __getitem__(self, ndx): querysets_count_zip = zip(self.querysets, self.querysets_counts) length = 0 # 加上本数组后的大数组长度 pre_length = 0 # 不包含本数组的大数组长度 items = [] # 返回的值 loop = 0 if isinstance(ndx, slice): ndx_start = ndx.start or 0 ndx_stop = ndx.stop or self.total_count ndx_step = ndx.step or 1 else: ndx_start = ndx ndx_stop, ndx_step = None, None for queryset, count in querysets_count_zip: length += count loop += 1 # 取当前数组的start角标, 存在3中情况 # 1. start角标在当前数组 if length > ndx_start >= pre_length: start = ndx_start - pre_length # print("[loop {}] Start is: {}".format(loop, start)) if ndx_step is None: return queryset[start] # 2. 不包含当前数组,因为起始已经超过了当前数组的长度 elif ndx_start >= length: pre_length += count continue # 3. 不在当前数组,但是应该从当前数组0开始计算 else: start = 0 # 可能取单个值, ndx_stop 为None, 不应该再找 if ndx_stop is None: pre_length += count continue # 取当前数组的stop角标, 存在2中情况 # 不存在第3中情况是因为找到了会提交结束循环 # 1. 结束角标小于length代表 结束位在当前数组上 if ndx_stop < length: stop = ndx_stop - pre_length # 2. 结束位置包含改数组到了最后 else: stop = count # print("[loop {}] Slice: {} {} {}".format(loop, start, stop, ndx_step)) items.extend(list(queryset[slice(start, stop, ndx_step)])) pre_length += count # 如果结束再当前数组,则结束循环 if ndx_stop < length: break return items