Simply use:
MyModel.objects.order_by('?').first()
It is documented in QuerySet API.
ID : 20067
viewed : 28
Tags : pythondjangodjango-modelspython
100
87
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]
77
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.
61
Here's a simple solution:
from random import randint count = Model.objects.count() random_object = Model.objects.all()[randint(0, count - 1)] #single random object
51
You could create a manager on your model to do this sort of thing. To first understand what a manager is, the Painting.objects
method is a manager that contains all()
, filter()
, get()
, etc. Creating your own manager allows you to pre-filter results and have all these same methods, as well as your own custom methods, work on the results.
EDIT: I modified my code to reflect the order_by['?']
method. Note that the manager returns an unlimited number of random models. Because of this I've included a bit of usage code to show how to get just a single model.
from django.db import models class RandomManager(models.Manager): def get_query_set(self): return super(RandomManager, self).get_query_set().order_by('?') class Painting(models.Model): title = models.CharField(max_length=100) author = models.CharField(max_length=50) objects = models.Manager() # The default manager. randoms = RandomManager() # The random-specific manager.
Usage
random_painting = Painting.randoms.all()[0]
Lastly, you can have many managers on your models, so feel free to create a LeastViewsManager()
or MostPopularManager()
.