从Django获取多个随机对象时,查询集如何工作?

时间:2014-11-29 23:20:18

标签: python django django-models django-queryset

我需要从Django模型中获取多个随机对象。

我知道我可以通过键入:

从模型Person中获取一个随机对象
person = Person.objects.order_by('?')[0]

然后,我在How to get two random records with Django中看到了一些建议,我可以通过以下方式做到这一点:

people = Person.objects.order_by('?')[0:n]

但是,只要我添加[0:n],Django就不会返回对象,而是返回一个QuerySet对象。如果我要求

,这会导致不幸的后果
print(people[0].first_name, people[0].last_name)

我为2个不同的人获取first_name和last_name,因为QuerySets在被调用时被评估(对吗?)。如何获取第一个查询返回的实际人员列表?

我正在使用Python 3.4.0和Django 1.7.1

2 个答案:

答案 0 :(得分:0)

试试这个......

people = []
for person in Person.objects.order_by('?')[0:n]:
    people.append(person)

答案 1 :(得分:0)

Simeon Popov的回答解决了这个问题,但让我来解释它的来源。

您可能知道查询集是惰性的,在有必要之前不会进行评估。它们还有一个内部缓存,一旦评估了整个查询集,就会被填充。如果只从查询集(或指定了step的切片,即[0:n:2])中获取单个对象,Django会对其进行评估,但结果不会被缓存。

采取以下两个例子:

示例1

>>> people = Person.objects.order_by('?')[0:n]
>>> print(people[0].first_name, people[0].last_name)
# first and last name of different people

示例2

>>> people = Person.objects.order_by('?')[0:n]
>>> for person in people:
>>>     print(person.first_name, person.last_name)
# first and last name are properly matched

在示例1中,当您访问第一个项目时,尚未评估查询集。它不会被缓存,因此当您再次访问第一个项目时,它会在数据库上运行另一个查询。

在第二个示例中,循环遍历整个查询集。因此,缓存已填满,并且不会有任何其他数据库查询会更改返回项的顺序。在这种情况下,名称彼此正确对齐。

评估整个查询集的方法是a.o.迭代,list()bool()len()。这些方法之间存在一些细微差别。如果您只想确保查询集被缓存,我建议使用bool(),即:

>>> people = Person.objects.order_by('?')[0:n]
>>> bool(people)
True
>>> print(people[0].first_name, people[0].last_name)
# matching names