Введение во внешние ключи в Django
Что такое внешний ключ и зачем он нужен
Внешний ключ (Foreign Key) в Django — это способ установить связь между двумя моделями (таблицами в базе данных). Он позволяет ссылаться на записи из одной таблицы из другой, обеспечивая целостность данных и упрощая выполнение запросов, связанных с этими данными. Например, у вас есть модель Автор
и модель Книга
. Каждая книга написана каким-то автором. Внешний ключ позволяет указать, какой именно автор написал данную книгу.
Определение внешнего ключа в моделях Django
В Django внешний ключ определяется с помощью поля ForeignKey
в одной из моделей. Это поле указывает на другую модель, с которой устанавливается связь. При определении внешнего ключа важно указать, что делать с зависимыми записями при удалении связанной записи. Это определяется параметром on_delete
.
Пример: Модели ‘Автор’ и ‘Книга’
from django.db import models
class Author(models.Model):
name: str = models.CharField(max_length=100)
bio: str = models.TextField()
def __str__(self) -> str:
return self.name
class Book(models.Model):
title: str = models.CharField(max_length=200)
author: Author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')
publication_date: models.DateField()
def __str__(self) -> str:
return self.title
В этом примере модель Book
имеет внешний ключ author
, который ссылается на модель Author
. Параметр on_delete=models.CASCADE
означает, что при удалении автора все связанные с ним книги будут также удалены. related_name='books'
позволяет получить доступ ко всем книгам автора через атрибут author.books
.
Получение данных связанной таблицы через внешний ключ
Прямой доступ к связанным данным
Имея экземпляр модели, содержащей внешний ключ, можно получить доступ к связанным данным напрямую через этот внешний ключ.
Использование атрибута связанной модели
book: Book = Book.objects.first()
author: Author = book.author # Получаем объект Author, связанный с данной книгой
print(author.name)
Примеры запросов для извлечения данных автора книги
from django.shortcuts import get_object_or_404
book: Book = get_object_or_404(Book, pk=1)
print(f"Книга: {book.title}, Автор: {book.author.name}")
Обратный доступ к данным через внешний ключ
Понятие обратного отношения (related_name)
Обратное отношение позволяет получить доступ к данным из таблицы, на которую ссылается внешний ключ. По умолчанию Django создает обратное отношение с именем [имя_модели]_set
. Однако, рекомендуется явно указывать related_name
.
Использование related_name для запросов
related_name
задается при определении внешнего ключа и позволяет удобно получать связанные объекты.
Пример: Получение всех книг автора
author: Author = Author.objects.first()
books: models.QuerySet[Book] = author.books.all() # Получаем все книги автора
for book in books:
print(book.title)
Если related_name не определен
Если related_name
не указан, можно использовать имя модели в нижнем регистре с суффиксом _set
для получения обратной связи. Например, author.book_set.all()
.
Запросы, включающие связанные данные (selectrelated и prefetchrelated)
Проблема N+1 запросов
При использовании внешних ключей часто возникает проблема N+1 запросов. Это когда для получения данных каждой связанной модели выполняется отдельный запрос к базе данных. Например, при выводе списка книг с авторами, для каждой книги будет выполнен отдельный запрос на получение информации об авторе. Это сильно замедляет работу приложения.
Использование select_related для оптимизации запросов (один-к-одному, один-ко-многим)
select_related
используется для оптимизации запросов, когда связь является типом