How to pull a random record using Django's ORM?
Simply use:
MyModel.objects.order_by('?').first()
It is documented in QuerySet API.
Using order_by('?')
will kill the db server on the second day in production. A better way is something like what is described in Getting a random row from a relational database.
from django.db.models.aggregates import Count
from random import randint
class PaintingManager(models.Manager):
def random(self):
count = self.aggregate(count=Count('id'))['count']
random_index = randint(0, count - 1)
return self.all()[random_index]
The solutions with order_by('?')[:N] are extremely slow even for medium-sized tables if you use MySQL (don't know about other databases).
order_by('?')[:N]
will be translated to SELECT ... FROM ... WHERE ... ORDER BY RAND() LIMIT N
query.
It means that for every row in table the RAND() function will be executed, then the whole table will be sorted according to value of this function and then first N records will be returned. If your tables are small, this is fine. But in most cases this is a very slow query.
I wrote simple function that works even if id's have holes (some rows where deleted):
def get_random_item(model, max_id=None):
if max_id is None:
max_id = model.objects.aggregate(Max('id')).values()[0]
min_id = math.ceil(max_id*random.random())
return model.objects.filter(id__gte=min_id)[0]
It is faster than order_by('?') in almost all cases.