Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django prefetch_related's Prefetch, order_by?

Tags:

django

I figured the following query:

 context['user_artists'] = Artist.objects.filter(users=current_user).all()

Coupled with the following usage in templates:

{% if user_artists %}
    ...
    {% for artist in user_artists %}
        ....
        <p class="small">last release: {{ artist.release_groups.last.title }}</p>
        <p class="small">date: {{ artist.release_groups.last.release_date }}</p>

Was hitting the database 3 times for every artist in the query. I know this can be brought down to 2 by simple saving .last in the template, but that still isn't fast enough.

I know I can use prefetch_related like so:

Artist.objects.filter(users=current_user).prefetch_realted(`release_groups`).all()

And I also need eliminate he usage of .last since it implies another query. I can probably use the template engine's slice method to get the last element. But then I have to order the related relationship: meaning, I need release_group ordered by its own release_date before I access them in the template. This must not affect the order of the artist objects.

How can this be done?

like image 999
zerohedge Avatar asked Jan 03 '18 04:01

zerohedge


1 Answers

You can use Prefetch:

Artist.objects.prefetch_related(Prefetch('release_groups', queryset=ReleaseGroup.objects.order_by('release_date')))

To avoid collision with the name, you can set to_attr to a different name:

Artist.objects.prefetch_related(Prefetch('release_groups', queryset=ReleaseGroup.objects.order_by('release_date'), to_attr='rgs')).all()

You can then access each cached release group in the template like so:

artist.rgs.0.title

like image 152
neverwalkaloner Avatar answered Oct 01 '22 23:10

neverwalkaloner