Foreign Keys
Part of the Models and the Admin section of Coddy's Django journey. Lesson 16 of 23.
Two of your books are by Jane Austen, and her name is typed in both: fix a typo and you fix it twice. Keep each author once, in a table of their own, and let each book point to its author. That pointer is a ForeignKey. A Loan, a book you lent to a friend, would point to its book:
class Loan(models.Model):
book = models.ForeignKey(Book, on_delete=models.PROTECT)
friend = models.CharField(max_length=100)
lent_on = models.DateField()The column stores the book's id, book_id; in Python, loan.book is the Book itself. Many loans can point to one book: a many-to-one relationship.
on_delete is required: it says what happens to the loans when their book is deleted. CASCADE deletes them too, PROTECT refuses to delete the book, and SET_NULL empties the field, which then needs null=True.
An Author model is ready, and its __str__ is the name, so {{ book.author }} in your templates keeps working.
Challenge
MediumIn books/models.py, change Book.author from text to a link to Author. When an author is deleted, their books are deleted with them.
Press Run and open the Data tab: books.Author holds the six authors, and the book rows hold their ids.
Try it yourself
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
class Meta:
ordering = ["name"]
def __str__(self):
return self.name
class Book(models.Model):
class Genre(models.TextChoices):
FICTION = "fiction", "Fiction"
SCIFI = "scifi", "Science fiction"
MYSTERY = "mystery", "Mystery"
HISTORY = "history", "History"
title = models.CharField(max_length=200)
author = models.CharField(max_length=100)
year = models.IntegerField()
price = models.DecimalField(max_digits=6, decimal_places=2)
is_read = models.BooleanField(default=False)
finished = models.DateField(null=True, blank=True)
summary = models.TextField(blank=True)
genre = models.CharField(max_length=20, choices=Genre, default=Genre.FICTION)
class Meta:
ordering = ["title"]
def __str__(self):
return f"{self.title} by {self.author}"
All lessons in Models and the Admin
Practice on your own: Django playground