Django how to shuffle a queryset without speed lose
I want to shuffle a list of objects without losing any speed in terms of optimization and performance speed. let's say I have the following query.
related_products = Announcement.objects.filter(category=category).exclude(id=announcement.id)
pythonically, i would import the random module and then random.shuffle(related_products). But I am not sure if it will store something in the memory on my view or use some CPU speed or whatever terminology I don't know.
So I wonder what's the best way to make it optimized.
Thanks!
If the list of related_products objects is reasonably short and if you are going to be using them all in any case, It's simplest to just fetch them and then shuffle them.
import random
...
products = random.shuffle( list( related_products) )
for product in products:
...
This is efficient, in that no objects are copied. The main issue is if it's possible that the quantity is excessive. You can use related_products.count() to find out how many there are, before fetching any from the DB.
There's also queryset .order_by('?') which retrieves in random order, but the documentation says "Note: order_by('?') queries may be expensive and slow, depending on the database backend you’re using."
A third possibility for sampling would be to fetch just the primary keys of every row in the table. Shuffle and slice those to get a sample of the required size, then fetch just those objects.
product_pks = related_products.values_list('pk', flat=True)
sampled_pks = random.shuffle( list(product_pks))[:N_SAMPLE]
products = related_products.filter( pk__in = sampled_pks )
No idea how this would perform, but it's two DB queries and the first fetches the minimum amount of data necessary for shuffling.