Menu
CoddyTech

Внешние ключи

Часть раздела Модели и панель администратора путешествия по Django на Coddy. Урок 16 из 23.

Две ваши книги написаны Джейн Остин, и её имя указано в обеих: исправьте опечатку — и придётся исправлять её дважды. Храните каждого автора один раз в отдельной таблице, а пусть каждая книга ссылается на своего автора. Такой указатель — это ForeignKey. Объект Loan — запись о книге, которую вы одолжили другу, — будет ссылаться на свою книгу:

class Loan(models.Model):
    book = models.ForeignKey(Book, on_delete=models.PROTECT)
    friend = models.CharField(max_length=100)
    lent_on = models.DateField()

В столбце хранится идентификатор книги, book_id; в Python loan.book — это сама книга Book. Несколько записей о займах могут ссылаться на одну книгу: это связь «многие к одному».

Параметр on_delete обязателен: он задаёт, что произойдёт с записями о займах, когда книга будет удалена. CASCADE удаляет и их, PROTECT запрещает удалять книгу, а SET_NULL очищает поле; в этом случае также требуется null=True.

Модель Author уже готова, а её метод __str__ возвращает имя, поэтому {{ book.author }} в ваших шаблонах продолжит работать.

challenge icon

Задание

Средне

В books/models.py измени Book.author с текстового поля на ссылку на Author. Когда автор удаляется, его книги удаляются вместе с ним.

Нажми «Играть» и выбери Dune: на странице по-прежнему указано «by Frank Herbert».

Попробуйте сами

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}"

Все уроки раздела Модели и панель администратора

Потренируйтесь самостоятельно: Песочница Django