About Adding Extra Field Values to Many-to-many Relations

To add extra fields to the many-to-many relation, you can use the through model. When you add an object to the relation, the extra fields can be added via through_defaults attribute:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
>>> from django.utils.timezone import now
>>> from readinglist.models import Book, Reader, BookToRead
>>> book = Book.objects.create(
...     title="Django 3 Web Development Cookbook", 
...     authors="Aidas Bendoraitis, Jake Kronika")
>>> reader = Reader.objects.create(name="Wannabe Djangonaut")
>>> reader.reading_list.add(book, through_defaults={
...     "priority": 1, "added_date": now()})
>>> reader.reading_list.all()
<QuerySet [<Book: Django 3 Web Development Cookbook>]>
>>> book.reader_set.all()
<QuerySet [<Reader: Wannabe Djangonaut>]>

Here the models of the readinglist are defined as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from django.db import models

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

    def __str__(self):
        return self.title

class Reader(models.Model):
    name = models.CharField(max_length=200)
    reading_list = models.ManyToManyField(
        Book, through="BookToRead", through_fields=("reader", "book")
    )

    def __str__(self):
        return self.name

class BookToRead(models.Model):
    book = models.ForeignKey(Book, on_delete=models.CASCADE)
    reader = models.ForeignKey(Reader, on_delete=models.CASCADE)
    priority = models.PositiveIntegerField()
    added_date = models.DateTimeField()

    def __str__(self):
        return f"{self.reader} wants to read {self.book}"

Programming Development Django 4.2 Django 3.2 Django 2.2