Queryset needs to be custom sorted into dictonary
can I have sort my queryset in custom order. By custom I mean for every ten products I receive, the first two should be featured (set to true), while the remaining eight should be unfeatured. This pattern should be repeated for each set of ten products and saved to a dictionary. The dictionary should save the data in the format of 'id':'rank'
. if is_featured
is same look at rank
.The database should be hited one time.
Product.objects.all().order_by('rank', '-created').values('is_featured', 'id', 'rank')
<EavQuerySet [{'is_featured': True, 'id': 19, 'rank': -20241209}, {'is_featured': True, 'id': 18, 'rank': -20241209},
{'is_featured': True, 'id': 17, 'rank': -20241209}, {'is_featured': True, 'id': 16, 'rank': -20241209}, {'is_featured': True, 'id': 15, 'rank': -20241209},
{'is_featured': False, 'id': 14, 'rank': -20241209}, {'is_featured': False, 'id': 13, 'rank': -20241209}, {'is_featured': False, 'id': 12, 'rank': -20241209}, {'is_featured': False, 'id': 11, 'rank': -20241209},
{'is_featured': False, 'id': 10, 'rank': -20241209}, {'is_featured': False, 'id': 9, 'rank': -20241209}, {'is_featured': False, 'id': 8, 'rank': -20241209}, {'is_featured': True, 'id': 7, 'rank': -20241206},
{'is_featured': True, 'id': 6, 'rank': -20241206}, {'is_featured': False, 'id': 1, 'rank': -20241128}, {'is_featured': True, 'id': 4, 'rank': -20241128},
{'is_featured': False, 'id': 5, 'rank': 0}, {'is_featured': False, 'id': 2, 'rank': 0}, {'is_featured': False, 'id': 3, 'rank': 0}]>
Just process the items by splitting these in two iterators after fetching the data, so:
from itertools import groupby, zip_longest
from operator import attrgetter
products = Product.objects.order_by('is_featured', 'rank', '-created')
items = {k: list(vs) for k, vs in groupby(products, attrgetter('is_featured'))}
featured = items.get(True, ())
featured = [featured[n : n + 2] for n in range(0, len(featured), 2)]
unfeatured = items.get(False, ())
unfeatured = [unfeatured[n : n + 8] for n in range(0, len(unfeatured), 8)]
result = {
k: k.rank
for fe, unfe in zip_longest(featured, unfeatured, fillvalue=())
for k in (*fe, *unfe)
}
This will make a dictionary that maps Product
objects to the old rank, and in the order of first two featured ones, then eight unfeatured, then two featured, etc.