如何用Django获取两个随机记录
我想知道怎么用Django获取两个不同的随机记录。我看到过关于怎么获取一条记录的问题,但我需要获取两条随机记录,而且这两条记录必须不一样。
7 个回答
11
给未来的读者。
首先,获取所有记录的ID列表:
my_ids = MyModel.objects.values_list('id', flat=True)
my_ids = list(my_ids)
然后,从上面所有的ID中随机挑选n个ID:
n = 2
rand_ids = random.sample(my_ids, n)
最后,获取这些ID对应的记录:
random_records = MyModel.objects.filter(id__in=rand_ids)
106
其他回答中提到的 order_by('?')[:2]
这个方法,对于行数很多的表来说,其实是个非常糟糕的选择。它会导致生成一个 ORDER BY RAND()
的 SQL 查询。举个例子,假设你的表有十亿行数据:
- 为了实现
ORDER BY RAND()
,数据库需要一个RAND()
列来进行排序。 - 为了有这个列,它需要创建一个新表(因为现有的表没有这个列)。
- 接着,mysql 会创建一个新的临时表,并把现有的十亿行数据复制过去。
- 在复制的过程中,它会按照你的要求,为每一行运行 rand() 来生成随机数。没错,你让 mysql 生成了十亿个随机数。这可得花费一段时间。:)
- 几小时或几天后,当这个过程完成后,它还得对这些数据进行排序。是的,你让 mysql 对这十亿行数据进行排序,而排序的依据是随机数,这样的排序效率是最差的。
- 几天或几周后,当排序完成后,它才会把你真正需要的那两行数据提取出来并返回给你。真是辛苦了。;)
注意:为了让事情更复杂一点,mysql 最开始会尝试在内存中创建那个临时表。当内存不够用时,它会暂停操作,把所有数据复制到硬盘上,这样几乎整个过程都会遇到 I/O 瓶颈。
如果你对此有疑问,可以查看生成的查询,确认它是 ORDER BY RAND()
,然后在谷歌上搜索 "order by rand()"(记得加上引号)。
一个更好的解决方案是,用三个便宜的查询来替代这个非常昂贵的查询(使用 limit/offset,而不是 ORDER BY RAND()
):
import random
last = MyModel.objects.count() - 1
index1 = random.randint(0, last)
# Here's one simple way to keep even distribution for
# index2 while still gauranteeing not to match index1.
index2 = random.randint(0, last - 1)
if index2 == index1: index2 = last
# This syntax will generate "OFFSET=indexN LIMIT=1" queries
# so each returns a single record with no extraneous data.
MyObj1 = MyModel.objects.all()[index1]
MyObj2 = MyModel.objects.all()[index2]
26
如果你在ORM中指定了随机操作符,我很确定它会给你两个不同的随机结果,对吧?
MyModel.objects.order_by('?')[:2] # 2 random results.