Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django can we select related a field on a prefetch related model?

Tags:

django

Assuming these as django model for the sake of simplcity:

class A():      a = manytomany('B')  class B():      b = charfield()     z = foreignkey('C')  class C():      c = charfield() 

Can we do something like this to fetch the z also:

foo = A.objects.get(pk = 1).prefetch_related('a').select_related('a__z') 
like image 891
Faris Nasution Avatar asked Dec 20 '12 13:12

Faris Nasution


People also ask

What does prefetch related do in Django?

In Django, select_related and prefetch_related are designed to stop the deluge of database queries that are caused by accessing related objects. In this article, we will see how it reduces the number of queries and make the program much faster.

How does select related work?

We use select_related when the object that you're going to select is a single object, which means forward ForeignKey, OneToOne and backward OneToOne . select_related works by creating an SQL join and including the fields of the related object in the SELECT statement.

What is QuerySet in Django?

A QuerySet is a collection of data from a database. A QuerySet is built up as a list of objects. QuerySets makes it easier to get the data you actually need, by allowing you to filter and order the data.


2 Answers

This answer is correct with versions of Django prior to 1.7. It produces three queries: first, fetch the instance of A, then fetch its related instances of B and finally fetch the instances of C related to those of B fetched in the second query.

Before Django 1.7, this is the best you can do, even though the second query could, in theory, select all B objects together with the related C objects joined through the z ForeignKey.

Starting with Django 1.7, there's a more advanced django.db.models.Prefetch class which allows you to do just that. With Prefetch you can customize the queryset used to prefetch related objects like this:

foo = A.objects.prefetch_related(     Prefetch('a', queryset=B.objects.select_related('z')) ).get(pk=1) 

This results in only two queries (as opposed to three when using prefetch_related('a__z')) and lets the database take care of the second join, which should in theory result in slightly better performance.

like image 105
koniiiik Avatar answered Oct 07 '22 05:10

koniiiik


You only need one prefetch_related call:

foo = A.objects.prefetch_related('a__z').get(pk=1) 

This will prefetch both tables. In Django 1.7+ you can improve performance by using a Prefetch object, as in koniiiik's answer.

like image 32
Alasdair Avatar answered Oct 07 '22 05:10

Alasdair