83π
Just been looking at this. The line:
random_object = A.objects.order_by('?')[0]
has reportedly brought down many servers.
Unfortunately Erwans code caused an error on accessing non-sequential ids.
There is another short way to do this:
import random
items = list(Product.objects.all())
# change 3 to how many random items you want
random_items = random.sample(items, 3)
# if you want only a single random item
random_item = random.choice(items)
The good thing about this is that it handles non-sequential ids without error.
34π
Improving on all of the above:
from random import choice
pks = A.objects.values_list('pk', flat=True)
random_pk = choice(pks)
random_obj = A.objects.get(pk=random_pk)
We first get a list of potential primary keys without loading any Django object, then we randomly choose one primary key, and then we load the chosen object only.
- [Django]-Django-rest-framework http put failing with 415 on django 1.5
- [Django]-Django string to date format
- [Django]-What's the best way to migrate a Django DB from SQLite to MySQL?
12π
The second bit of code is correct, but can be slower, because in SQL that generates an ORDER BY RANDOM()
clause that shuffles the entire set of results, and then takes a LIMIT
based on that.
The first bit of code still has to evaluate the entire set of results. E.g., what if your random_idx is near the last possible index?
A better approach is to pick a random ID from your database, and choose that (which is a primary key lookup, so itβs fast). We canβt assume that our every id
between 1
and MAX(id)
is available, in the case that youβve deleted something. So following is an approximation that works out well:
import random
# grab the max id in the database
max_id = A.objects.order_by('-id')[0].id
# grab a random possible id. we don't know if this id does exist in the database, though
random_id = random.randint(1, max_id + 1)
# return an object with that id, or the first object with an id greater than that one
# this is a fast lookup, because your primary key probably has a RANGE index.
random_object = A.objects.filter(id__gte=random_id)[0]
- [Django]-Django 1.4 β can't compare offset-naive and offset-aware datetimes
- [Django]-Django Template Ternary Operator
- [Django]-Celery: WorkerLostError: Worker exited prematurely: signal 9 (SIGKILL)
7π
How about calculating maximal primary key and getting random pk?
The book βDjango ORM Cookbookβ compares execution time of the following functions to get random object from a given model.
from django.db.models import Max
from myapp.models import Category
def get_random():
return Category.objects.order_by("?").first()
def get_random3():
max_id = Category.objects.all().aggregate(max_id=Max("id"))['max_id']
while True:
pk = random.randint(1, max_id)
category = Category.objects.filter(pk=pk).first()
if category:
return category
Test was made on a million DB entries:
In [14]: timeit.timeit(get_random3, number=100)
Out[14]: 0.20055226399563253
In [15]: timeit.timeit(get_random, number=100)
Out[15]: 56.92513192095794
See source.
After seeing those results I started using the following snippet:
from django.db.models import Max
import random
def get_random_obj_from_queryset(queryset):
max_pk = queryset.aggregate(max_pk=Max("pk"))['max_pk']
while True:
obj = queryset.filter(pk=random.randint(1, max_pk)).first()
if obj:
return obj
So far it did do the job as long as there is an id.
Notice that the get_random3 (get_random_obj_from_queryset) function wonβt work if you replace model id with uuid or something else. Also, if too many instances were deleted the while loop will slow the process down.
- [Django]-What's the cleanest, simplest-to-get running datepicker in Django?
- [Django]-How to solve "Page not found (404)" error in Django?
- [Django]-Exclude a field from django rest framework serializer
1π
Yet another way:
pks = A.objects.values_list('pk', flat=True)
random_idx = randint(0, len(pks)-1)
random_obj = A.objects.get(pk=pks[random_idx])
Works even if there are larger gaps in the pks, for example if you want to filter the queryset before picking one of the remaining objects at random.
EDIT: fixed call of randint (thanks to @Quique). The stop arg is inclusive.
https://docs.python.org/3/library/random.html#random.randint
- [Django]-Django content-type : how do I get an object?
- [Django]-Why use Django on Google App Engine?
- [Django]-How to use Cassandra in Django framework
0π
Iβm sharing my latest test result with Django 2.1.7, PostgreSQL 10.
students = Student.objects.all()
for i in range(500):
student = random.choice(students)
print(student)
# 0.021996498107910156 seconds
for i in range(500):
student = Student.objects.order_by('?')[0]
print(student)
# 0.41299867630004883 seconds
It seems that random fetching with random.choice() is about 2x faster.
- [Django]-Generics vs viewset in django rest framework, how to prefer which one to use?
- [Django]-Django β what is the difference between render(), render_to_response() and direct_to_template()?
- [Django]-Gunicorn + nginx: Server via socket or proxy?
0π
Taking Djangoβs lazy database access into account, the naive time for selecting a random element basically comes down to the time it takes to run len(A.obejcs.all())
.
On the database I am trying this out on, it takes a few seconds to do this.
The solution sugested below is instant.
A better way is to wrap the query in a Paginator
object:
import random
from django.core.paginator import Paginator, Page
paginator = Paginator(Sample.objects.all().order_by('pk'), 25)
random_page = paginator.get_page(random.choice(paginator.page_range))
random_sample = random.choice(random_page.object_list)
The 25
pages per pagination is just a guess for a good value.
So basically, we choose a random page, and in that page we choose a random sample.
- [Django]-How to set up custom middleware in Django?
- [Django]-Django model fields validation
- [Django]-Django test RequestFactory vs Client
-1π
in python for getting a random member of a iterable object
like list,set, touple
or anything else you can use random
module.
random
module have a method named choice
, this method get a iterable
object and return a one of all members randomly.
so becouse random.choice
want a iterable object you can use this method for queryset
in django.
first import the random module:
import random
then create a list:
my_iterable_object = [1, 2, 3, 4, 5, 6]
or create a query_set like this:
my_iterable_object = mymodel.objects.filter(name='django')
and for getting a random member of your iterable object use choice method:
random_member = random.choice(my_iterable_object)
print(random_member) # my_iterable_object is [1, 2, 3, 4, 5, 6]
3
full code:
import random
my_list = [1, 2, 3, 4, 5, 6]
random.choice(my_list)
2
- [Django]-Django templates: forloop.first and forloop.last
- [Django]-How to do SELECT MAX in Django?
- [Django]-Django test RequestFactory vs Client
-1π
import random
def get_random_obj(model, length=-1):
if length == -1:
length = model.objects.count()
return model.objects.all()[random.randint(0, length - 1)]
#to use this function
random_obj = get_random_obj(A)
- [Django]-Django's forms.Form vs forms.ModelForm
- [Django]-How do I get multiple values from checkboxes in Django
- [Django]-How to execute a Python script from the Django shell?