一尘不染

如何使用Django获取两个随机记录

django

如何使用Django获得两个不同的随机记录?我见过有关如何获得一个记录的问题,但我需要获得两个随机记录,而且它们必须有所不同。


阅读 422

收藏
2020-03-27

共2个答案

一尘不染

如果你在ORM中指定了随机运算符,我很确定它将为你提供两个不同的随机结果,不是吗?

MyModel.objects.order_by('?')[:2] # 2 random results.
2020-03-27
一尘不染

order_by('?')[:2]对于具有大量行的表,其他答案建议的解决方案实际上是一件非常糟糕的事情。它导致一个ORDER BY RAND()SQL查询。例如,这是mysql处理该问题的方式(其他数据库的情况没有太大不同)。假设你的表有十亿行:

  1. 要完成此操作ORDER BY RAND(),需要在其RAND()上进行排序。
  2. 为此,它需要一个新表(现有表没有这样的列)。
  3. 为此,mysql使用新的列创建一个新的临时表,并将现有的一十亿行数据复制到其中。
  4. 这样,它将按照你的要求进行操作,并为每行运行rand()来填充该值。是的,你已指示mysql生成十亿个随机数。这需要一段时间。:)
  5. 几个小时/天之后,现在必须对其进行排序。是的,你已指示mysql对这10亿行排序最坏的表排序(最坏的情况是因为排序键是随机的)。
  6. 几天/几周后,完成此操作后,它会忠实地获取你实际需要的两行,并为你退还。不错的工作。;)
    注意:仅需一点额外的注意,请注意mysql最初将尝试在RAM中创建该临时表。用完后,它会将所有内容都保留下来,以将整个内容复制到磁盘上,因此你几乎可以在整个过程中充分利用I / O瓶颈。

怀疑者应查看生成的查询,以确认该查询是否是ORDER BY RAND()Google的“按rand()订购”(带有引号)。

更好的解决方案是将一个真正昂贵的查询换成三个便宜的查询(限制/偏移量而不是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]
2020-03-27