If you prefer a single query and use MySQL , check out the excellent link provided by @Crazyshezy in his comment.
For PostgreSQL backends, a possible query is possible (provided that there are relations with zero FK values from Book to Author and from Author to Category ):
SELECT * FROM ( SELECT book_table.*, row_number() OVER (PARTITION BY category_id ORDER BY RANDOM()) AS rn FROM book_table INNER JOIN author_table ON book_table.author_id = author_table.id ) AS sq WHERE rn <= 5
You can then wrap it inside a RawQuerySet to get Book instances
from collections import defaultdict qs = Book.objects.raw("""The above sql suited for your tables...""") collection = defaultdict(list) for obj in qs: collection[obj.category_id].append(obj) categories_w_rand_books = [] for category in c: categories_w_rand_books.append((category, collection[category.id]))
You may not want to run this request for each request directly without caching.
In addition, your code generates no more than 50 * 5 = 250 Book s, randomly, I'm just wondering why, because it seems that there is too much for one page. Are items displayed as tabs or something else? Perhaps you could reduce the number of SQL queries by executing Ajax or simplifying the requirement?
Update
To use book.author without running another query, try prefetch_related_objects
from django.db.models.query import prefetch_related_objects qs = list(qs)
The above code preloads authors in a package and fills them in qs . It just adds another request.
okm
source share