0
0
Djangoframework~5 mins

Through model for extra fields on M2M in Django

Choose your learning style9 modes available
Introduction

Sometimes you want to connect two things with extra details about their connection. A through model lets you add those extra details between two related items.

You want to track the date when two items were linked together.
You need to store extra information about the relationship, like a role or status.
You want to customize how two models relate beyond a simple link.
You want to add notes or metadata about the connection between two models.
Syntax
Django
class ModelA(models.Model):
    name = models.CharField(max_length=100)

class ModelB(models.Model):
    name = models.CharField(max_length=100)
    related_as = models.ManyToManyField(ModelA, through='ThroughModel')

class ThroughModel(models.Model):
    modela = models.ForeignKey(ModelA, on_delete=models.CASCADE)
    modelb = models.ForeignKey(ModelB, on_delete=models.CASCADE)
    extra_field = models.CharField(max_length=100)

The through attribute tells Django to use your custom model for the relationship.

In the through model, you must have foreign keys to both related models.

Examples
This example shows authors linked to books with an extra field role describing their job.
Django
class Book(models.Model):
    title = models.CharField(max_length=100)

class Author(models.Model):
    name = models.CharField(max_length=100)
    books = models.ManyToManyField(Book, through='Authorship')

class Authorship(models.Model):
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
    book = models.ForeignKey(Book, on_delete=models.CASCADE)
    role = models.CharField(max_length=50)  # e.g., 'Writer', 'Editor'
This example tracks when a student joined a course using the date_joined field.
Django
class Student(models.Model):
    name = models.CharField(max_length=100)

class Course(models.Model):
    title = models.CharField(max_length=100)
    students = models.ManyToManyField(Student, through='Enrollment')

class Enrollment(models.Model):
    student = models.ForeignKey(Student, on_delete=models.CASCADE)
    course = models.ForeignKey(Course, on_delete=models.CASCADE)
    date_joined = models.DateField()
Sample Program

This example shows a sports team and players linked with extra info like when a player joined and their position.

Django
from django.db import models

class Player(models.Model):
    name = models.CharField(max_length=100)

class Team(models.Model):
    name = models.CharField(max_length=100)
    players = models.ManyToManyField(Player, through='Membership')

class Membership(models.Model):
    player = models.ForeignKey(Player, on_delete=models.CASCADE)
    team = models.ForeignKey(Team, on_delete=models.CASCADE)
    date_joined = models.DateField()
    position = models.CharField(max_length=50)

# Usage example (not part of models):
# Create objects and link with extra info
# p = Player.objects.create(name='Alice')
# t = Team.objects.create(name='Red Dragons')
# Membership.objects.create(player=p, team=t, date_joined='2024-01-15', position='Captain')
OutputSuccess
Important Notes

You cannot add extra fields directly on a normal ManyToManyField without a through model.

When using a through model, you manage the relationship by creating and updating the through model instances.

Remember to use on_delete=models.CASCADE to keep data consistent when deleting linked objects.

Summary

A through model lets you add extra details to a many-to-many relationship.

You create a separate model with foreign keys to both related models and extra fields.

Use the through parameter on ManyToManyField to connect your custom model.