Django得到一个随机对象

vjrehmav  于 2022-12-01  发布在  Go
关注(0)|答案(7)|浏览(105)

我试图从模型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]中的某些内容?

2ledvvac

2ledvvac1#

我刚看了这个。这句话:

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。

aelbi1ox

aelbi1ox2#

改善以上所有方面:

from random import choice

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

zaq34kh63#

第二部分代码是正确的,但可能会慢一些,因为在SQL中,会生成一个ORDER BY RANDOM()子句,该子句对整个结果集进行洗牌,然后基于此获取一个LIMIT
代码的第一位仍然需要计算整个结果集。例如,如果random_idx接近最后一个可能的索引,该怎么办?
一个更好的方法是从数据库中随机选择一个ID,并选择它(这是一个主键查找,所以速度很快)。我们不能假设在删除了某个内容的情况下,1MAX(id)之间的每个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]
ssgvzors

ssgvzors4#

如何计算最大主键并得到随机pk?
书“Django ORM Cookbook”比较了以下函数的执行时间,以从给定模型中获得随机对象。

from django.db.models import Max
from myapp.models import Category

def get_random():
    return Category.objects.order_by("?").first()

def get_random3():
    max_id = Category.objects.all().aggregate(max_id=Max("id"))['max_id']
    while True:
        pk = random.randint(1, max_id)
        category = Category.objects.filter(pk=pk).first()
        if category:
            return category

对一百万个DB条目进行了测试:

In [14]: timeit.timeit(get_random3, number=100)
Out[14]: 0.20055226399563253

In [15]: timeit.timeit(get_random, number=100)
Out[15]: 56.92513192095794

请参阅source
看到这些结果后,我开始使用以下代码片段:

from django.db.models import Max
import random

def get_random_obj_from_queryset(queryset):
    max_pk = queryset.aggregate(max_pk=Max("pk"))['max_pk']
    while True:
        obj = queryset.filter(pk=random.randint(1, max_pk)).first()
        if obj:
            return obj

到目前为止,只要有一个id,它就能完成这项工作。注意,如果用uuid或其他东西替换模型id,get_random3(get_random_obj_from_queryset)函数将不起作用。此外,如果删除了太多示例,while循环将减慢进程。

8ljdwjyq

8ljdwjyq5#

又道:

pks = A.objects.values_list('pk', flat=True)
random_idx = randint(0, len(pks)-1)
random_obj = A.objects.get(pk=pks[random_idx])

即使pk中存在较大的间隔也有效,例如,如果您希望在随机选取剩余对象之一之前过滤查询集。
编辑:修复了randint的调用(感谢@Quique)。停止参数是包含的。
https://docs.python.org/3/library/random.html#random.randint

z0qdvdin

z0qdvdin6#

我正在分享我最近的测试结果与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倍。

bfnvny8b

bfnvny8b7#

在python中,要获取iterable object的随机成员,如list,set, touple或其他任何内容,可以使用random模块。
random模块有一个名为choice方法,该方法获取一个iterable对象,并随机返回所有成员中的一个。
所以因为random.choice想要一个可迭代对象,你可以在django中为queryset使用这个方法。
首先导入随机模块:

import random

然后创建一个列表:

my_iterable_object = [1, 2, 3, 4, 5, 6]

或者创建如下所示的query_set:

my_iterable_object = mymodel.objects.filter(name='django')

而要获取可迭代对象的随机成员,请使用choice方法:

random_member = random.choice(my_iterable_object)
print(random_member) # my_iterable_object is [1, 2, 3, 4, 5, 6]

3
完整代码:

import random

my_list = [1, 2, 3, 4, 5, 6]

random.choice(my_list)

2

相关问题