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.

Back to Top