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

时间:2009-11-13 19:27:42

标签: python django django-models random sql-order-by

如何使用Django获取两个不同的随机记录?我已经看到了关于如何获得一个的问题,但我需要获得两个随机记录,它们必须不同。

6 个答案:

答案 0 :(得分:96)

对于具有大量行的表,其他答案建议的order_by('?')[:2]解决方案实际上是一件非常糟糕的事情。它会导致ORDER BY RAND() SQL查询。作为一个例子,这里是mysql如何处理(其他数据库的情况没有太大差别)。想象一下你的桌子有十亿行:

  1. 要完成ORDER BY RAND(),需要RAND()列进行排序。
  2. 为此,它需要一个新表(现有表没有这样的列)。
  3. 为此,mysql使用新列创建一个新的临时表,并将现有的ONE BILLION ROWS OF DATA复制到其中。
  4. 当它这样做时,它会按照您的要求执行,并为每一行运行rand()以填充该值。是的,你已经指示mysql生成一个十亿随机数。这需要一段时间。 :)
  5. 几小时/几天后,当它完成时,它现在必须对它进行排序。是的,你已经指示mysql排序这个十亿行,最糟糕的情况下的表(最糟糕的情况是因为排序键是随机的)。
  6. 几天/几周之后,当它完成后,它忠实地抓住你实际需要的两个微不足道的行并为你返回它们。不错的工作。 ;)
  7. 注意:只是为了一点额外的肉汁,请注意mysql最初会尝试在RAM中创建临时表。当它耗尽时,它会将所有内容都保留下来,将整个内容复制到磁盘上,这样就可以在几乎整个过程中获得额外的I / O瓶颈。

    怀疑者应该查看生成的查询,以确认它是ORDER BY RAND()然后是谷歌“按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]
    

答案 1 :(得分:23)

如果在ORM中指定随机运算符我很确定它会给你两个截然不同的随机结果吗?

MyModel.objects.order_by('?')[:2] # 2 random results.

答案 2 :(得分:8)

为未来的读者。

获取所有记录的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)

答案 3 :(得分:6)

Object.objects.order_by('?')[:2]

这将返回两个随机排序的记录。你可以添加

distinct()

如果数据集中有相同值的记录。

答案 4 :(得分:3)

关于从序列中采样n个随机值,可以使用随机库,

random.Random().sample(range(0,last),2) 

将从序列元素中取出2个随机样本,0到last-1

答案 5 :(得分:0)

from django.db import models
from random import randint
from django.db.models.aggregates import Count


class ProductManager(models.Manager):
    def random(self, count=5):
        index = randint(0, self.aggregate(count=Count('id'))['count'] - count)
        return self.all()[index:index + count]

您可以获得不同数量的对象。