Python Django获得一个随机对象

Python Django获得一个随机对象,python,django,object,random,Python,Django,Object,Random,我试图从模型a中获得一个随机对象 目前,它与以下代码配合良好: random_idx = random.randint(0, A.objects.count() - 1) random_object = A.objects.all()[random_idx] 但我觉得这个代码更好: random_object = A.objects.order_by('?')[0] 哪一个是最好的?使用第一个代码删除的对象可能存在问题?因为,例如,我可以有10个对象,但是id为10的对象已经不存在了?我是否

我试图从模型a中获得一个随机对象

目前,它与以下代码配合良好:

random_idx = random.randint(0, A.objects.count() - 1)
random_object = A.objects.all()[random_idx]
但我觉得这个代码更好:

random_object = A.objects.order_by('?')[0]

哪一个是最好的?使用第一个代码删除的对象可能存在问题?因为,例如,我可以有10个对象,但是id为10的对象已经不存在了?我是否误解了A.objects.all[random_idx]中的某些内容?

第二位代码是正确的,但速度可能会慢一些,因为在SQL中,它生成一个ORDER BY random子句,该子句洗牌整个结果集,然后在此基础上进行限制

代码的第一位仍然需要评估整个结果集。例如,如果您的随机idx接近最后一个可能的索引,该怎么办

更好的方法是从数据库中选择一个随机ID,然后选择主键查找,这样速度更快。如果您删除了某些内容,我们不能假设1到MAXid之间的每个id都可用。下面是一个很好的近似值:

import random

# grab the max id in the database
max_id = A.objects.order_by('-id')[0].id

# grab a random possible id. we don't know if this id does exist in the database, though
random_id = random.randint(1, max_id + 1)

# return an object with that id, or the first object with an id greater than that one
# this is a fast lookup, because your primary key probably has a RANGE index.
random_object = A.objects.filter(id__gte=random_id)[0]

我一直在看这个。该行:

random_object = A.objects.order_by('?')[0]
据报道已经关闭了许多服务器

不幸的是,Erwans代码在访问非顺序ID时导致错误

还有另一个简单的方法可以做到这一点:

import random

items = list(Product.objects.all())

# change 3 to how many random items you want
random_items = random.sample(items, 3)
# if you want only a single random item
random_item = random.choice(items)
这样做的好处是,它处理非顺序ID时不会出错。

还有另一种方法:

pks = A.objects.values_list('pk', flat=True)
random_idx = randint(0, len(pks)-1)
random_obj = A.objects.get(pk=pks[random_idx])
即使pks中存在较大的间隙,也可以工作,例如,如果要在随机拾取剩余对象之一之前过滤查询集

编辑:修复了randint的呼叫,感谢@Quique。停止参数包含在内


我正在与Django 2.1.7、PostgreSQL 10分享我的最新测试结果

students=Student.objects.all 对于500范围内的i: 学生=random.choices学生 印刷学生 0.021996498107910156秒 对于500范围内的i: student=student.objects.order_by'?'[0] 印刷学生 0.4129986763004883秒
使用random.choice进行随机抓取的速度似乎快了2倍。

改进了上述所有方面:

from random import choice

pks = A.objects.values_list('pk', flat=True)
random_pk = choice(pks)
random_obj = A.objects.get(pk=random_pk)

您可以使用随机模块中的选择

from .models import MyModel
from random import choice    

MyRandomChoice = choice(MyModel.objects.all())

为什么要进行两次查询,一次用于计数,一次用于实际选择,而不是1?我认为第二次可能更好,但第一次不受您描述的问题的影响,因为它是对已绑定的列表进行索引,而不是根据数据库ID进行选择。另外,为什么不是random.choiceA.objects.all?可能是@Two Bitalchest blergh的副本,这是最糟糕的:从数据库中获取所有行以便只返回一行。@DanielRoseman它也非常可读,如果在其他地方使用,将A.objects.all保留为不同于解决方案2的顺序,并简要说明了另一个潜在的用例。我看不到任何关于性能的问题,只是什么会起作用,对于少数对象,可读性更重要。Django QuerySet中的切片被转换为SQL中的限制/偏移调用。我的意思是:SQL中的限制/偏移是出了名的慢,因为它几乎要计算整个列表。您应该替换get-by筛选器。现在出现以下错误:TypeError:“A”对象不支持索引。我将用pks替换所有ID。有关更多信息,请查看如果PKs中存在太多间隙(如在不断重新导入的表中),则此操作不起作用。查看random模块的文档random.sampleitems,1[0]可以通过使用random.choiceitems来避免。请参阅。如果要从random.choiceitems获取对象,请使用items=listProduct.objects.allThat应该是:random\u idx=randint0,lenpks-1它实际上应该是random\u pk=choicepks。虽然此代码片段可以解决问题,但确实有助于提高文章的质量。请记住,您将在将来回答读者的问题,这些人可能不知道您的代码建议的原因。还请尽量不要用解释性注释挤满你的代码,这会降低代码和解释的可读性!