8

So i got the database.objects.all() and database.objects.get('name') but how would i got about getting one random item from the database. I'm having trouble trying to figure out how to get it ot select one random item.

3 Answers 3

19

Selecting a random element from a list of all database objects isn't a goog solution as retrieving all elements of the database can have a big impact on performance, neither is using order_by('?') as mentioned in the django documentation.

The best solution should be to retrieve an element with a random index:

import random

random_idx = random.randint(0, Model.objects.count() - 1)
random_obj = Model.objects.all()[random_idx]
Sign up to request clarification or add additional context in comments.

5 Comments

Don't you think that Model.objects.all() is expensive? See me edited answer.
Do you have an explanation/benchmark showing this is faster than order_by('?')[0]? I know what the docs say but the key here is that the DB will select just 1 item and the speed would therefore be effectively the same (given a reasonably smart DB engine). order_by('?') would be really slow only if you're actually fetching more than one row..
@AamirAdnan: Of course the expensiveness will depend on your number of records and it's possible that it works well with a few records, but also if you would use values_list and you would have let's say millions of records, django will need to fetch the id of every object.
@Delyan:The database will have to apply a random ordering to all records in the selected table just to retrieve the first element then! An article about mysql: jan.kneschke.de/projects/mysql/order-by-rand
@lazerscience: I stand corrected, you're right. Kinda. :) See this gist - gist.github.com/1868909 - I recreated the Python code in SQL to avoid the jump between Python and Postgres. The table I'm running it on is small but the important thing to notice is the consistently slow execution time for ORDER BY RANDOM(). The runtime of the random offset alternative depends on the random index itself! Ordering by an index (i.e., forcing an index scan) makes the results a bit more consistent but still varying with the offset. But yes, you're right, it is faster.
2

Aamir's solution will select all objects before discarding all but one. This is extremely wasteful and, besides, this sort of calculation should be done in the database.

model.objects.all().order_by('?')[0]

Read more here: https://docs.djangoproject.com/en/dev/ref/models/querysets/#order-by

Edit: lazerscience's answer is indeed faster, as shown here.

1 Comment

This is also quite slow, as you can read at the link you provided: Note: order_by('?') queries may be expensive and slow...
-1

I would do it slightly different. Querysets are lazy anyway in django.

import random

def get_my_random_object():
    object = random.choice(model.objects.all())
    return object

https://docs.djangoproject.com/en/dev/topics/db/queries/#querysets-are-lazy https://docs.djangoproject.com/en/dev/ref/models/querysets/#when-querysets-are-evaluated

1 Comment

random.choice() calls len(queryset) (as seen in random.py). This will evaluate the entire queryset and pull it into memory before picking a single element.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.