我试图从模型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个对象但是数字10作为id的对象不再存在?我在A.objects.all()[random_idx]中误解了什么吗?
刚看过这个。这条线:
random_object = A.objects.order_by('?')[0]
据报道,它已经摧毁了许多服务器
不幸的是,Erwans代码在访问非顺序ID时导致错误。
还有另一种简短的方法:
import random
items = 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。
第二位代码是正确的,但可能会更慢,因为在SQL中生成一个ORDER BY RANDOM()
子句,它会对整个结果集进行混洗,然后根据它来获取LIMIT
。
第一部分代码仍然需要评估整个结果集。例如,如果你的random_idx接近最后一个可能的索引怎么办?
更好的方法是从数据库中选择一个随机ID,并选择它(这是一个主键查找,所以它很快)。我们不能假设我们在id
和1
之间的每个MAX(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]
另一种方式:
pks = A.objects.values_list('pk', flat=True)
random_idx = randint(0, len(pks))
random_obj = A.objects.get(pk=pks[random_idx])
即使pks中存在较大的间隙,也可以工作,例如,如果要在随机选择其中一个剩余对象之前过滤查询集。
我正在与Django 2.1.7,PostgreSQL 10分享我最新的测试结果。
students = Student.objects.all()
for i in range(500):
student = random.choice(students)
print(student)
# 0.021996498107910156 seconds
for i in range(500):
student = Student.objects.order_by('?')[0]
print(student)
# 0.41299867630004883 seconds
使用random.choice()进行随机提取似乎要快2倍。