def _ordered_iterator(self):
"""An iterator that takes into account the requested ordering."""
# A mapping of iterable to the current item in that iterable. (Remember
# that each QuerySet is already sorted.)
not_empty_qss = [iter(it) for it in self._querysets if it]
values = {it: next(it) for it in not_empty_qss}
# The offset of items returned.
index = 0
# Create a comparison function based on the requested ordering.
_comparator = self._generate_comparator(self.order_by)
def comparator(i1, i2):
# Actually compare the 2nd element in each tuple, the 1st element is
# the generator.
return _comparator(i1[1], i2[1])
comparator = functools.cmp_to_key(comparator)
# If in reverse mode, get the last value instead of the first value from
# ordered_values below.
if self.standard_ordering:
next_value_ind = 0
else:
next_value_ind = -1
# Iterate until all the values are gone.
while values:
# If there's only one iterator left, don't bother sorting.
if len(values) > 1:
# Sort the current values for each iterable.
ordered_values = sorted(values.items(), key=comparator)
# The next ordering item is in the first position, unless we're
# in reverse mode.
qss, value = ordered_values.pop(next_value_ind)
else:
qss, value = list(values.items())[0]
# Return it if we're within the slice of interest.
if self.low_mark <= index:
yield value
index += 1
# We've left the slice of interest, we're done.
if index == self.high_mark:
return
# Iterate the iterable that just lost a value.
try:
values[qss] = next(qss)
except StopIteration:
# This iterator is done, remove it.
del values[qss]
# TODO Inherit from django.db.models.base.Model.
评论列表
文章目录