如何有效地获取过滤查询集的随机元素?

How to get a random element of the filtered queryset efficiently?

我尝试通过这种方式从已过滤的查询集中提取随机对象:

Product.objects.filter(active=True).order_by('?').first()

目前用.order_by('?')解决了,但是好像很慢。

我尝试实现 this question 我认为的解决方案。

它不起作用,所以我不确定我的做法是否正确。

products = Product.objects.filter(
    active=True,
)
count = products.aggregate(count=Count('id'))['count']
random_index = randint(0, count - 1)
product = products[random_index]

现在这是我的代码,它抛出 ValueError:

ValueError: low >= high

请帮我加快速度。

你可以这样做:

import random

products = Product.objects.filter(
    active=True,
)
items = list(products)

# if you want only a single random item
random_item = random.choice(items)  

或这个:

from random import randint

count = Product.objects.count()

try:
    random_choice = randint(0, count - 1)
except:
    # if count == 0 then it will raise a ValueError.
    random_choice = 0  

random_object = Product.objects.none()
if random_choice > 0:
    random_object = Product.objects.all()[random_choice]  

P.s1: 第二种方案效率更高。
P.s2: 不要使用 order_by('?').

如果 .order_by('?') 太慢,一个不错的选择(取决于产品的数量)可能是查询项目的 PK,然后随机选择一个:

qs = Product.objects.filter(active=True)
pks = list(qs.values_list('id', flat=True))
random_pk = random.choice(active_product_pks)
random_item = qs.get(pk=random_pk)

如果满足您的业务需求,您也可以在 Django 缓存中缓存 pks 一段时间。