Django得到一个随机对象

Erw*_*wan 4 python random django object

我试图从模型A中获取一个随机对象

目前,它正在使用此代码:

random_idx = random.randint(0, A.objects.count() - 1)
random_object = A.objects.all()[random_idx]
Run Code Online (Sandbox Code Playgroud)

但我觉得这段代码更好:

random_object = A.objects.order_by('?')[0]
Run Code Online (Sandbox Code Playgroud)

哪一个是最好的?使用第一个代码删除对象可能出现问题?因为,例如,我可以有10个对象但是数字10作为id的对象不再存在?我在A.objects.all()[random_idx]中误解了什么吗?

luk*_*aus 11

刚看过这个.这条线:

random_object = A.objects.order_by('?')[0]
Run Code Online (Sandbox Code Playgroud)

据报道,它已经摧毁了许多服务器

不幸的是,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)
Run Code Online (Sandbox Code Playgroud)

这样做的好处是它可以无错误地处理非顺序ID.

  • 查看`random`模块的文档,可以使用`random.choice(items)`避免`random.sample(items, 1)[0]`。参见 [random.choice](https://docs.python.org/3/library/random.html#random.choice)。 (4认同)
  • 请注意,如果您的产品表非常大,您将在内存中加载所有产品,这会很快填满内存。我认为@km6提出的values_list('pk', flat=True)方法在这方面更好。 (4认同)
  • 如果您想从“random.choice(items)”获取对象,请使用“items = list(Product.objects.all())” (2认同)

Paw*_*Kam 7

计算最大主键并获得随机 pk 怎么样?

\n

\xe2\x80\x98 Django ORM Cookbook \xe2\x80\x99书比较以下函数的执行时间,以从给定模型中获取随机对象。

\n
from django.db.models import Max\nfrom myapp.models import Category\n\ndef get_random():\n    return Category.objects.order_by("?").first()\n\ndef get_random3():\n    max_id = Category.objects.all().aggregate(max_id=Max("id"))[\'max_id\']\n    while True:\n        pk = random.randint(1, max_id)\n        category = Category.objects.filter(pk=pk).first()\n        if category:\n            return category\n
Run Code Online (Sandbox Code Playgroud)\n

对一百万个数据库条目进行了测试:

\n
In [14]: timeit.timeit(get_random3, number=100)\nOut[14]: 0.20055226399563253\n\nIn [15]: timeit.timeit(get_random, number=100)\nOut[15]: 56.92513192095794\n
Run Code Online (Sandbox Code Playgroud)\n

参见源码

\n

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

\n
from django.db.models import Max\nimport random\n\ndef get_random_obj_from_queryset(queryset):\n    max_pk = queryset.aggregate(max_pk=Max("pk"))[\'max_pk\']\n    while True:\n        obj = queryset.filter(pk=random.randint(1, max_pk)).first()\n        if obj:\n            return obj\n
Run Code Online (Sandbox Code Playgroud)\n

到目前为止,只要有 id,它就可以完成这项工作。\n请注意,如果将模型 id 替换为 uuid 或其他内容,则 get_random3 (get_random_obj_from_queryset) 函数将\xe2\x80\x99t 工作。此外,如果删除了太多实例,则 while 循环会减慢进程速度。

\n


Soh*_*ain 6

代码的第二位是正确的,但可能会更慢,因为在 SQL 中,它会生成一个ORDER BY RANDOM()子句,该子句将整个结果集打乱,然后LIMIT根据它进行处理。

代码的第一位仍然必须评估整个结果集。例如,如果您的 random_idx 接近最后一个可能的索引怎么办?

更好的方法是从数据库中随机选择一个 ID,然后选择它(这是一个主键查找,因此速度很快)。如果您删除了某些内容,我们不能假设我们id之间的每个1MAX(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]
Run Code Online (Sandbox Code Playgroud)

  • 不是很大的随机性。想象一下,您有 3 个对象,id 分别为 1、2 和 99(其他已删除)。在这种情况下,您的算法有 98% 的可能性返回 99 (2认同)

km6*_*km6 5

改进以上所有内容:

from random import choice

pks = A.objects.values_list('pk', flat=True)
random_pk = choice(pks)
random_obj = A.objects.get(pk=random_pk)
Run Code Online (Sandbox Code Playgroud)

  • 我最喜欢这个 (3认同)