← Назад к вопросам

Что такое ForeignKey в Django?

1.0 Junior🔥 181 комментариев
#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# ForeignKey в Django

ForeignKey — это полевой тип в Django ORM, который создаёт связь один-ко-многим (one-to-many) между двумя моделями. Он хранит ссылку на первичный ключ связанного объекта.

Базовый синтаксис

from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField()

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
    published_date = models.DateField()

Здесь каждая книга (Book) связана с одним автором (Author). В БД это создаст колонку author_id, которая хранит id автора.

Параметр on_delete

Отвечает за поведение при удалении связанного объекта:

# CASCADE — удалить все связанные объекты
author = models.ForeignKey(Author, on_delete=models.CASCADE)

# SET_NULL — установить NULL (требует null=True)
author = models.ForeignKey(Author, on_delete=models.SET_NULL, null=True)

# SET_DEFAULT — установить значение по умолчанию
author = models.ForeignKey(Author, on_delete=models.SET_DEFAULT, default=1)

# PROTECT — запретить удаление (выбросить ошибку)
author = models.ForeignKey(Author, on_delete=models.PROTECT)

# DO_NOTHING — ничего не делать (может нарушить целостность)
author = models.ForeignKey(Author, on_delete=models.DO_NOTHING)

Использование в коде

# Создание объекта
author = Author.objects.create(name="Толстой", email="tolstoy@example.com")
book = Book.objects.create(
    title="Война и мир",
    author=author,  # Можно передать объект
    published_date="1869-01-01"
)

# Или через id
book = Book.objects.create(
    title="Война и мир",
    author_id=1,  # Или через id
    published_date="1869-01-01"
)

# Доступ к связанному объекту
print(book.author.name)  # "Толстой"
print(book.author_id)    # 1

Обратные связи (Reverse Relations)

# Получить все книги автора
author = Author.objects.get(id=1)
books = author.book_set.all()

# Или с кастомным именем (related_name)
class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(
        Author,
        on_delete=models.CASCADE,
        related_name='books'  # Кастомное имя обратной связи
    )

# Теперь используем
books = author.books.all()

# Фильтрация в обратном направлении
authors_with_published_books = Author.objects.filter(
    books__published_date__year=2023
)

Параметры ForeignKey

author = models.ForeignKey(
    Author,                           # Целевая модель
    on_delete=models.CASCADE,         # Поведение при удалении
    related_name='books',             # Имя для обратной связи
    related_query_name='book',        # Имя для фильтров
    db_column='author_id',            # Имя колонки (редко)
    null=True,                        # Может ли быть NULL
    blank=True,                       # Может ли быть пусто в форме
    limit_choices_to={'active': True}, # Ограничить choices в админке
    to_field='id'                     # На какое поле ссылаться (по умолчанию pk)
)

Оптимизация запросов

# Плохо: N+1 problem
for book in Book.objects.all():
    print(book.author.name)  # Запрос в БД для каждой книги

# Хорошо: select_related
for book in Book.objects.select_related('author'):
    print(book.author.name)  # Один запрос с JOIN

ForeignKey vs OneToOneField

# ForeignKey — один автор может иметь много книг
author = models.ForeignKey(Author, on_delete=models.CASCADE)

# OneToOneField — один автор, один профиль
author_profile = models.OneToOneField(AuthorProfile, on_delete=models.CASCADE)

Самореферентные связи

# Для дерева категорий, комментариев и т.п.
class Category(models.Model):
    name = models.CharField(max_length=100)
    parent = models.ForeignKey(
        'self',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='children'
    )

# Использование
root = Category.objects.create(name="Электроника")
phones = Category.objects.create(name="Телефоны", parent=root)

Миграции

# Если добавили ForeignKey к существующей модели
# Django спросит значение для старых записей
# Либо используй default, либо null=True+blank=True

author = models.ForeignKey(
    Author,
    on_delete=models.CASCADE,
    default=1  # Или null=True для пустого значения
)

Важные моменты

  1. Индексы — ForeignKey автоматически создаёт индекс в БД (ускоряет фильтры и JOIN)
  2. Целостность — БД проверяет, что ссылаемый объект существует
  3. Производительность — используй select_related() для оптимизации
  4. Каскадное удаление — внимательнее с CASCADE, может удалить неожиданно много данных
  5. Обратные запросы — используй related_name для читаемости кода

ForeignKey — это основа реляционных моделей в Django. Правильное использование критично для целостности и производительности приложения.