如何使用Django的ORM提取随机记录?

2024-05-23 12:09:35 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个模型,代表我在我的网站上呈现的绘画。在主网页上,我想展示其中的一些:最新的,一个大多数时间没有访问过的,最受欢迎的和一个随机的。

我用的是Django 1.0.2。

虽然前3个很容易使用django模型,但最后一个(随机)会给我带来一些麻烦。在我看来,我可以把它编码成这样:

number_of_records = models.Painting.objects.count()
random_index = int(random.random()*number_of_records)+1
random_paint = models.Painting.get(pk = random_index)

在我看来,这并不是我想要的东西——这完全是数据库抽象的一部分,应该在模型中。另外,在这里我需要处理删除的记录(那么所有记录的数量不会覆盖我所有可能的键值)以及可能的其他很多事情。

有没有其他的方法我可以做到,最好是在模型抽象里面?


Tags: ofdjango模型网页numberindex网站models
3条回答

按('?')顺序排列的解[:N]如果使用MySQL(不知道其他数据库),即使对于中等大小的表也是非常慢的。

order_by('?')[:N]将转换为SELECT ... FROM ... WHERE ... ORDER BY RAND() LIMIT N查询。

这意味着对于表中的每一行,将执行RAND()函数,然后根据该函数的值对整个表进行排序,然后首先返回N条记录。如果你的桌子很小,就可以了。但在大多数情况下,这是一个非常缓慢的查询。

我编写了一个简单的函数,即使id有漏洞也能工作(删除了一些行):

def get_random_item(model, max_id=None):
    if max_id is None:
        max_id = model.objects.aggregate(Max('id')).values()[0]
    min_id = math.ceil(max_id*random.random())
    return model.objects.filter(id__gte=min_id)[0]

它比按('?')订购快几乎在所有情况下。

简单使用:

MyModel.objects.order_by('?').first()

它记录在QuerySet API中。

使用order_by('?')将在生产的第二天杀死数据库服务器。更好的方法是像Getting a random row from a relational database中描述的那样。

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

class PaintingManager(models.Manager):
    def random(self):
        count = self.aggregate(count=Count('id'))['count']
        random_index = randint(0, count - 1)
        return self.all()[random_index]

相关问题 更多 >

    热门问题