How to select random record with Django ORM
This post details how I solved displaying random banner on this very site. The solution does not have any prerequisites.
Published: Sept. 8, 2020 Sponsored App StoreRecently I wanted to implement more sophisticated banners on this site to promote my iOS apps. Initially I had just one hardcoded banner in the template but that was not going to work for multiple banners.
The part that took the longest was to display random banner on a page. This involves mainly getting random record (or entity if you will) from your database. I have found quite a few solutions but they were either too complicated or relied on some preconditions like you had to have a table with no deleted records + sequential ids and then you could use something like last id or count and select random number from that.
My solution does not have any requirements but could be problematic if you needed to select from possibly 100s of thousands or more records.
Anyway, let's move to code. My Banner
s can be toggled off with property is_active
so I am using Django ORM filter
together with values
to pull out all the available ids. Like this:
banner_ids = Banner.objects.filter(is_active=True).values('id')
Once that is done, we can check if the result is not empty and if not, utilize choice
form random
module to pick random element.
import random
if len(banner_ids) > 0:
random_id = random.choice(banner_ids)["id"]
try:
banner = Banner.objects.get(pk=random_id)
except Banner.DoesNotExist:
banner = None
Because the banners_ids
is basically "array" of key-value pairs, there is ["id"]
subscript to pull out just the number. Once we have random id, we can use that to try to get record with the get
method.
And that is all!
I think this is pretty good for my usecase and for many other assuming you don't have tons of data to work with.
I have a few banners and the pages are cached so I don't almost have to even think about performance.
Note on memory usage
I have been recently informed by a reader that the above method might be memory intensive in certain situations. Theirs was Raspberry Pi and presumably large number of records.
A solution for this situation can be to use order_by("?")[0]
which does random ordering at the database level and uses less memory.