← Back to Django Course | Chapter 6: Advanced ORM Queries | Lesson 6 of 9

One-to-Many Relationships

A one-to-many relationship is like one parent having many children — one Chapter can have many Tutorials, but each Tutorial has only one Chapter.

Modeling One-to-Many

One-to-many means one row on one side can relate to many rows on the other side — implemented by putting a ForeignKey on the many model.

Example: Modeling One-to-Many

One Chapter can be the parent of many Tutorial rows, each pointing back to it through the chapter field.

markup
from django.db import models

class Chapter(models.Model):
    title = models.CharField(max_length=200)

class Tutorial(models.Model):
    chapter = models.ForeignKey(
        Chapter, related_name='tutorials', on_delete=models.CASCADE
    )
    title = models.CharField(max_length=200)
{# Django-only code -- models.py/views.py/urls.py/settings.py snippets, or template markup using Django template tags/variables -- can't run standalone via Judge0 or the browser preview, since it needs a real Django project. Only this course's pure-Python examples (example_lang == 'python', no Django imports) are actually runnable, so those still get the button below. #}

Looking Up Children from the Parent

related_name gives you a friendly way to go from the one side back to all its related many rows.

Note: Without related_name, Django defaults to modelname_set, like chapter.tutorial_set.all().

Example: Looking Up Children from the Parent

Because related_name=tutorials was set on the ForeignKey, chapter.tutorials.all() returns every Tutorial linked to this chapter.

markup
from core.models import Chapter

chapter = Chapter.objects.first()
chapter.tutorials.all()
{# Django-only code -- models.py/views.py/urls.py/settings.py snippets, or template markup using Django template tags/variables -- can't run standalone via Judge0 or the browser preview, since it needs a real Django project. Only this course's pure-Python examples (example_lang == 'python', no Django imports) are actually runnable, so those still get the button below. #}

on_delete Behavior

on_delete tells Django what to do to child rows when their parent is deleted — CASCADE deletes them too, SET_NULL clears the link instead.

Warning: Choosing CASCADE by default can silently delete more data than intended.

Example: on_delete Behavior

If the related Chapter is deleted, this Tutorial's chapter field becomes null instead of the Tutorial itself being deleted.

markup
from django.db import models

class Tutorial(models.Model):
    chapter = models.ForeignKey(
        'Chapter', null=True, on_delete=models.SET_NULL
    )
{# Django-only code -- models.py/views.py/urls.py/settings.py snippets, or template markup using Django template tags/variables -- can't run standalone via Judge0 or the browser preview, since it needs a real Django project. Only this course's pure-Python examples (example_lang == 'python', no Django imports) are actually runnable, so those still get the button below. #}
Common Mistakes
  1. Thinking the many side needs a ManyToManyField instead of a plain ForeignKey — a ForeignKey on the many model is enough.
  2. Forgetting the reverse accessor name (default is modelname_set, e.g. chapter.tutorial_set) or the custom related_name if one was set.
  3. Not choosing an appropriate on_delete behavior, leaving CASCADE by accident when SET_NULL was intended.
Chapter Summary
  • One-to-many is modeled with a single ForeignKey on the many side.
  • The one side can look up all its related rows using the reverse relation, e.g. chapter.tutorials.all().
  • on_delete controls what happens to child rows when the parent is deleted.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.