如何在Django/postgreSQL中从数据库中随机获取一个项目?

7

我得到了database.objects.all()和database.objects.get('name'),但如何从数据库中获取一个随机项目呢?我很难想象如何选择一个随机项目。

3个回答

18
从所有数据库对象列表中选择一个随机元素并不是一个好的解决方案,因为检索数据库的所有元素可能会对性能产生很大影响,使用order_by('?')也不是一个好的选择,正如django documentation中所述。
最好的解决方案应该是检索具有随机索引的元素:
import random

random_idx = random.randint(0, Model.objects.count() - 1)
random_obj = Model.objects.all()[random_idx]

你不认为 Model.objects.all() 很耗费资源吗?看看我编辑过的答案。 - Aamir Rind
您有解释或基准可以显示这比order_by('?')[0]更快吗?我知道文档中说了什么,但关键在于DB只会选择一个项目,因此速度实际上是相同的(如果使用相当智能的DB引擎)。如果您实际上正在获取多行,order_by('?')的速度会非常慢。 - Delyan
@AamirAdnan:当然,昂贵程度取决于您的记录数量,如果您只有一些记录,它可能会很好地工作,但是如果您使用values_list并且有数百万条记录,Django将需要获取每个对象的id - Bernhard Vallant
@Delyan:数据库将不得不对选定表中的 所有 记录应用随机排序,以便检索第一个元素!有关mysql的文章:http://jan.kneschke.de/projects/mysql/order-by-rand/ - Bernhard Vallant
1
@lazerscience:我改正了,你是对的。有点。:) 请看这个gist - https://gist.github.com/1868909 - 我将Python代码重新创建为SQL,以避免在Python和Postgres之间跳转。我正在运行它的表很小,但需要注意的重要事情是ORDER BY RANDOM()的执行时间始终较慢。随机偏移替代方案的运行时取决于随机索引本身!按索引排序(即强制进行索引扫描)使结果更加一致,但仍然会因偏移而不同。但是,没错,你是对的,它确实更快。 - Delyan

2

3
这也相当慢,正如您提供的链接中所述:注意:order_by('?')查询可能很昂贵且缓慢... - Bernhard Vallant

-1

5
random.choice() 调用了 len(queryset)(在 random.py 中可以看到)。这将评估整个 queryset 并将其全部加载到内存中,然后再从中选择一个元素。 - knbk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接