How do queries work when getting multiple random objects from Django?

I need to get some random objects from a Django model.

I know I can get one random object from the Person model by typing:

person = Person.objects.order_by('?')[0]

      

Then I saw suggestions in How to get two random entries with Django saying that I could just do this:

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

      

However, as soon as I add this [0: n], instead of returning objects, Django returns a QuerySet object. This leads to unfortunate consequences, which if I then ask

print(people[0].first_name, people[0].last_name)

      

I am getting first_name and last_name for two different people as QuerySets are evaluated as they are called (correct?). How do I get the actual list of people that were returned from the first request?

I am using Python 3.4.0 and Django 1.7.1

+3


source to share


2 answers


Simeon Popov's answer solves the problem, but let me explain where it came from.

As you probably know, queries are lazy and won't evaluate until needed. They also have an internal cache that fills up after evaluating the entire request. If only one object is selected from the set of queries (or a slice with the specified one step

, i.e. [0:n:2]

), Django evaluates it, but the results will not be cached.

Let's take two examples:

Example 1

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

      

Example 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

      

In example 1, the set of queries is not yet evaluated when the first item is accessed. It will not be cached, so when you open the first item again, it runs another query on the database.

In the second example, the entire set of queries is evaluated as you iterate over it. This way the cache fills up and there won't be any additional database queries that change the order of the returned items. In this case, the names are correctly aligned with each other.

Assessment methods just a set of queries: ao iteration list()

, bool()

and len()

. There are some subtle differences between these methods. If all you want to do is make sure the request has been cached, I would suggest using bool()

, ie:

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

      

0


source


Try it...



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

      

0


source







All Articles