I see this example of to_attr
in Django document about Prefetch and I don’t quite understand why these two statements are different link
>>> Question.objects.prefetch_related(prefetch).get().voted_choices
[<Choice: The sky>]
>>> Question.objects.prefetch_related(prefetch).get().choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
First, the common case:
This is a query returning a single instance of Question
, with the related Choice
objects retrieved and associated with that instance.
Then looking at the second statement:
it adds the reference to the related object manager (choice_set
) and returns the related Choice
objects as a QuerySet. (Among other things, this means that you could chain additional queryset methods on to it, such as a values
function.)
This:
needs to be understood in the context of the previous definition of voted_choices
which is:
voted_choices = Choice.objects.filter(votes__gt=0)
and:
prefetch = Prefetch('choice_set', queryset=voted_choices, to_attr='voted_choices')
The to_attr
parameter means that the Question
instance being returned by that query is going to have a new attribute named voted_choices
referencing the list defined by the voted_choices
query. That is what is being demonstrated by the use of the .voted_choices
reference on the first query.
It might be more clear to you if you were to refactor the code and think about it like this:
a_question = Question.objects.prefetch_related(prefetch).get(pk=1)
a_question.choice_set.all()
^^^^^^^^^^^^^^ # Returns all objects from the related manager
a_question.voted_choices
^^^^^^^^^^^^^ # Returns the new attribute defined by `prefetch`