Bird
Raised Fist0
Djangoframework~10 mins

Relationship query patterns in Django - Step-by-Step Execution

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Concept Flow - Relationship query patterns
Define Models with Relationships
Create QuerySet on Base Model
Use Related Field Lookups
Follow ForeignKey
Filter/Access Related Data
Use in Views/Templates
Shows how Django queries follow model relationships using field lookups to access related data.
Execution Sample
Django
books = Book.objects.filter(author__name='Alice')
for book in books:
    print(book.title, book.author.email)
Filters books by author's name and prints book title with author's email.
Execution Table
StepActionQuerySet StateResult/Output
1Call Book.objects.filter(author__name='Alice')QuerySet with SQL JOIN on author tableQuerySet of books with author named Alice
2Evaluate QuerySet by iteratingQuerySet evaluated, DB rows fetchedList of Book objects matching filter
3Access book.title and book.author.emailAccess related author via ForeignKeyPrint book title and author's email
4Loop continues for next bookSame as step 3Print next book info
5Loop ends after last bookIteration completeNo more output
💡 All books with author named 'Alice' processed, iteration ends
Variable Tracker
VariableStartAfter 1After 2Final
booksQuerySet (unfetched)QuerySet (unfetched)Book(id=1, title='X', author=Author(id=1))QuerySet exhausted
bookNoneNoneBook(id=1, title='X', author=Author(id=1))Last book processed
Key Moments - 3 Insights
How does Django know to join the author table when filtering by author__name?
Django uses the double underscore '__' syntax to follow ForeignKey relationships, so 'author__name' tells it to join the author table and filter by its name field, as shown in execution_table step 1.
When accessing book.author.email, does Django hit the database again?
Yes, it performs a lazy query. The filter JOIN is only for filtering (WHERE clause); it does not select author fields. Thus, book.author.email triggers an additional DB query per book. Use select_related('author') to prefetch via JOIN without extra queries.
What happens if no books match the filter author__name='Alice'?
The QuerySet will be empty, so the loop won't run and no output prints. This is shown by an empty QuerySet state in variable_tracker and no iteration in execution_table.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what is the QuerySet state after step 1?
AQuerySet with SQL JOIN on author table
BEmpty QuerySet
CList of Book objects
DSingle Book object
💡 Hint
Refer to execution_table row with Step 1 under 'QuerySet State'
At which step does Django fetch data from the database?
AStep 1
BStep 2
CStep 3
DStep 5
💡 Hint
Check execution_table row Step 2 where QuerySet is evaluated and DB rows fetched
If we change filter to author__name='Bob', how does variable 'books' change after step 1?
AEmpty QuerySet
BContains books with author named Alice
CContains books with author named Bob
DRaises error
💡 Hint
Look at variable_tracker for 'books' and how filter changes QuerySet content
Concept Snapshot
Django Relationship Query Patterns:
- Use double underscore '__' to follow related fields in filters
- ForeignKey, OneToOne, ManyToMany can be traversed
- QuerySets use JOINs to filter by related data (select_related/prefetch_related to fetch efficiently)
- Access related objects via attributes (e.g., book.author.email)
- Lazy evaluation: Query runs when data is needed
- Empty QuerySet means no matching records
Full Transcript
This visual execution trace shows how Django queries follow relationships between models. First, models define relationships like ForeignKey. Then, a QuerySet is created using filters with double underscores to follow related fields, such as author__name. The QuerySet compiles a SQL JOIN to filter by related data efficiently. When iterating the QuerySet, Django fetches data from the database. Accessing related fields uses lazy loading (extra queries) unless prefetched (e.g., select_related). If no records match, the QuerySet is empty and no iteration occurs. This pattern helps retrieve related data efficiently with proper prefetching, improving performance and code clarity.

Practice

(1/5)
1. In Django, how do you filter a queryset to get all Book objects where the related Author model's name is 'Alice'?
easy
A. Book.objects.filter(author.name='Alice')
B. Book.objects.filter(name__author='Alice')
C. Book.objects.filter('author.name'='Alice')
D. Book.objects.filter(author__name='Alice')

Solution

  1. Step 1: Understand Django's double underscore syntax for related fields

    In Django ORM, to filter by a related model's field, use double underscores between the related model name and the field name.
  2. Step 2: Apply the correct filter syntax

    Here, author__name='Alice' correctly filters books whose author's name is 'Alice'.
  3. Final Answer:

    Book.objects.filter(author__name='Alice') -> Option D
  4. Quick Check:

    Related field filter uses __ = A [OK]
Hint: Use double underscores to filter related model fields [OK]
Common Mistakes:
  • Using dot notation instead of double underscores
  • Reversing the field and model names
  • Passing strings incorrectly in filter
2. Which of the following is the correct syntax to use select_related to optimize a query fetching Book objects with their related Author data?
easy
A. Book.objects.select_related(['author']).all()
B. Book.objects.select_related(author).all()
C. Book.objects.select_related('author').all()
D. Book.objects.select_related('author__name').all()

Solution

  1. Step 1: Recall the correct argument type for select_related

    select_related accepts one or more string arguments naming related fields to follow.
  2. Step 2: Check the syntax for passing related field names

    Passing a string like 'author' is correct. Passing a variable without quotes or a list is incorrect.
  3. Final Answer:

    Book.objects.select_related('author').all() -> Option C
  4. Quick Check:

    select_related takes string field names [OK]
Hint: Pass related field names as strings to select_related [OK]
Common Mistakes:
  • Passing variables without quotes
  • Using lists instead of strings
  • Including field names beyond direct relations
3. Given these models:
class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)

What will this query return?
books = Book.objects.filter(author__name__startswith='J')
medium
A. All authors whose name starts with 'J'
B. All books whose author's name starts with 'J'
C. All books with title starting with 'J'
D. Syntax error due to incorrect filter

Solution

  1. Step 1: Understand the filter condition

    The filter uses author__name__startswith='J', which means it looks at the related author's name starting with 'J'.
  2. Step 2: Determine the queryset result

    The queryset returns Book objects whose related Author name starts with 'J'.
  3. Final Answer:

    All books whose author's name starts with 'J' -> Option B
  4. Quick Check:

    Filter on related field with startswith = A [OK]
Hint: Filter related fields with double underscores and lookups [OK]
Common Mistakes:
  • Confusing filtering on book title instead of author name
  • Thinking the query returns authors instead of books
  • Misusing lookup syntax causing errors
4. Identify the error in this Django query:
Book.objects.prefetch_related('author__books').all()

Assuming Author has a reverse relation books to Book.
medium
A. No error, the query is correct
B. The lookup 'author__books' is invalid for prefetch_related
C. prefetch_related requires a list, not a string
D. prefetch_related cannot follow reverse relations

Solution

  1. Step 1: Understand prefetch_related capabilities

    prefetch_related supports double-underscore chained lookups across forward (FK) and reverse relations.
  2. Step 2: Validate the lookup 'author__books'

    From Book, 'author' follows the FK to Author, then 'books' follows the reverse relation to Book objects. This is valid and prefetches all books per author.
  3. Final Answer:

    No error, the query is correct -> Option A
  4. Quick Check:

    prefetch_related supports FK + reverse chains [OK]
Hint: prefetch_related supports chained lookups including reverse relations [OK]
Common Mistakes:
  • Thinking prefetch_related cannot chain to reverse relations
  • Passing a list instead of a string
  • Assuming prefetch_related cannot follow reverse relations
5. You want to efficiently fetch all Book objects along with their Author and the Publisher related to the author. The models are:
class Publisher(models.Model):
    name = models.CharField(max_length=100)

class Author(models.Model):
    name = models.CharField(max_length=100)
    publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)

Which query optimizes database hits best?
hard
A. Book.objects.select_related('author', 'author__publisher').all()
B. Book.objects.prefetch_related('author', 'author__publisher').all()
C. Book.objects.select_related('author').prefetch_related('author__publisher').all()
D. Book.objects.all()

Solution

  1. Step 1: Understand select_related vs prefetch_related

    select_related follows foreign keys with SQL JOINs, efficient for single-valued relations. prefetch_related is for many-to-many or reverse relations.
  2. Step 2: Analyze the relations

    Both author and author__publisher are foreign keys (single-valued), so select_related is best to reduce queries.
  3. Final Answer:

    Book.objects.select_related('author', 'author__publisher').all() -> Option A
  4. Quick Check:

    Use select_related for foreign keys chains [OK]
Hint: Use select_related for foreign key chains to reduce queries [OK]
Common Mistakes:
  • Using prefetch_related for foreign keys
  • Not chaining related fields in select_related
  • Fetching all without optimization