M
M
Mekalure2019-08-28 13:16:23
Django
Mekalure, 2019-08-28 13:16:23

Django ORM: How to sort by prefetched_set?

Let's say there are two models: Person and Numbers (ForeignKey on Person, number and more fields)
I get all persons along with numbers. But the numbers are additionally filtered so that numbers_set will either have one value or none. The numbers_set itself can have multiple values, but I specifically need one or none.

persons = Person.objects.all().prefecth_related(Prefecth('numbers_set', queryset=<numbers_filter>))

The problem is sorting. I need to sort Person by the value of the number, but sorting goes by the first met number in general, and not by those that are preloaded in Prefetch
. And the root of the problem is that I need different sortings by Person fields and by numbers. I sort by fields normally using order_by, but by numbers I have to sorted (person, key =), which is not very convenient and correct.
Is it possible to somehow sort the ORM as I want? order_by accepts QueryExpressions, but I still can't figure out what exactly to pass to it

Answer the question

In order to leave comments, you need to log in

1 answer(s)
W
werevolff, 2019-08-28
@Mekalure

And what you get in prefetch cannot be somehow driven through the annotation? And then sort from the annotation?
In general, can use the to_attr argument to rename an attribute?
class Prefetch(lookup, queryset=None, to_attr=None)
The to_attr argument sets the result of the prefetch operation to a custom attribute.
I assume numbers_set can refer to an existing object field.
Solution found via FilteredRelation() . Mekalureexplanation: Actually, the Prefetch() method does not create an attribute that is available in order_by. I ran it at home: this attribute is not available in annotate either. Only as a result of sampling. Therefore, sorting by it will not work. FilteredRelation() is declared inside annotate and creates a QuerySet available in order_by and subsequent filtering. But, alas, this QuerySet will not be available in the selection results. I suspect that Dzhanga is able to connect two QuerySets only through prefetch_related, but not through annotate. In any case, this function makes the desired data available when sorting.
It turns out:

qs1 = Model1.objects.filter(**kwargs)
qs2 = Model2.objects.annotate(order=FilteredRelation('lookup', condition=Q(**kwarg))).prefetch_related(Prefetch('lookup', queryset=qs1)).order_by('order')

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question