JavaRush /Курсы /Модуль 3: Django /Связь ForeignKey: как связать модели

Связь ForeignKey: как связать модели

Модуль 3: Django
9 уровень , 2 лекция
Открыта

Сегодня мы перейдем к более распространенному типу связи, который активно используется в реальных приложениях: связь один-ко-многим с использованием ForeignKey.

Что такое связь один-ко-многим?

Представьте, что у вас есть папка с документами. Папка — это "родитель", она может содержать множество "детей" (документов), но каждый документ относится только к одной папке. Это и есть отношение один-ко-многим (One-to-Many).

С точки зрения реляционной базы данных, связь один-ко-многим выглядит как:

  • Одна запись в первой таблице (родитель) может быть связана с несколькими записями во второй таблице (дети).
  • Каждая запись во второй таблице ссылается только на одну запись в первой таблице.

В Django такая связь реализуется с помощью поля ForeignKey.

Когда использовать связь ForeignKey?

ForeignKey является наиболее часто используемым типом связи, который прекрасно подходит в следующих сценариях:

  1. Магазин и его товары: один магазин может продавать множество продуктов, но каждый продукт принадлежит одному магазину.
  2. Статьи и авторы: один автор может написать множество статей, но каждая статья написана одним автором.
  3. Категории и продукты: одна категория может содержать множество продуктов, но каждый продукт принадлежит только одной категории.

Реализация связи один-ко-многим через ForeignKey

Давайте реализуем простой пример. Представим, что у нас есть система управления блогом, состоящая из двух моделей: Author и Post. Один автор может написать множество постов.

Шаг 1: создаём модели

from django.db import models

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

    def __str__(self):
        return self.name


class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    author = models.ForeignKey(Author, on_delete=models.CASCADE)

    def __str__(self):
        return self.title

Разберём код:

  1. Модель Author:

    • Содержит имя name и email email автора.
    • Поле __str__ возвращает имя автора для удобного отображения.
  2. Модель Post:

    • Содержит заголовок title, контент content и ссылку на автора через поле author.
    • Поле author использует ForeignKey, указывая на модель Author.
  3. Ключевой параметр в ForeignKeyon_delete:

    • Здесь мы указали on_delete=models.CASCADE, что означает: если запись родительской таблицы Author удаляется, то все связанные посты Post также будут автоматически удалены.

Шаг 2: выполняем миграции

После описания моделей необходимо сделать миграции, чтобы изменения вступили в силу в базе данных.

python manage.py makemigrations
python manage.py migrate

Шаг 3: добавляем данные

Теперь давайте создадим несколько авторов и постов в Django shell.

python manage.py shell
# Импортируем наши модели
from blog.models import Author, Post

# Создаём авторов
author_1 = Author.objects.create(name="Иван Иванов", email="ivan@example.com")
author_2 = Author.objects.create(name="Анна Смирнова", email="anna@example.com")

# Создаём посты
post_1 = Post.objects.create(title="Первая статья", content="Содержимое статьи 1", author=author_1)
post_2 = Post.objects.create(title="Вторая статья", content="Содержимое статьи 2", author=author_1)
post_3 = Post.objects.create(title="Третья статья", content="Содержимое статьи 3", author=author_2)

Теперь у нас есть два автора (Иван и Анна) и три поста, которые относятся к ним.

Шаг 4: работа с записями

Получение связанных объектов. С помощью ForeignKey вы можете легко вытаскивать связанные записи:

# Получаем автора статьи
post = Post.objects.get(title="Первая статья")
print(post.author)  # Выведет: Иван Иванов

# Получаем все статьи автора
author = Author.objects.get(name="Иван Иванов")
posts = author.post_set.all()
print(posts)  # Выведет QuerySet с двумя статьями
Примечание:

Django автоматически создает related_name в формате modelname_set (в данном случае post_set) для обратной связи.

Создаём статьи через автора

Вы можете создавать статьи через модель Author, не указывая явным образом ForeignKey.

author = Author.objects.get(name="Анна Смирнова")
author.post_set.create(title="Четвертая статья", content="Содержимое статьи 4")

Поведение при удалении: on_delete

Важным моментом при использовании ForeignKey является указание поведения при удалении связанных объектов. Django предоставляет несколько опций:

  • CASCADE: удаляет все связанные объекты (по умолчанию).
  • SET_NULL: устанавливает значение NULL, если это разрешено полем.
  • PROTECT: выдает ошибку, если удаляются связанные записи.
  • DO_NOTHING: ничего не делает (не рекомендуется).
  • SET_DEFAULT: устанавливает значение по умолчанию.

Пример:

author = models.ForeignKey(Author, on_delete=models.SET_NULL, null=True, blank=True)

Примеры бизнес-сценариев

  1. Интернет-магазин:

    • Категория Category и Товары Product:

      class Category(models.Model):
          name = models.CharField(max_length=100)
      
      class Product(models.Model):
          name = models.CharField(max_length=100)
          category = models.ForeignKey(Category, on_delete=models.CASCADE)
      
  2. Система бронирования:

    • Комната Room и Бронирования Booking:
      class Room(models.Model):
          number = models.IntegerField()
      
      class Booking(models.Model):
          room = models.ForeignKey(Room, on_delete=models.PROTECT)
          date = models.DateField()

Частые ошибки и особенности

  1. Отсутствие миграций:

    • Не забудьте сделать миграции после добавления нового поля ForeignKey, иначе база данных не будет знать о ваших изменениях.
  2. Ошибка при удалении объектов:

    • Не указывайте on_delete=DO_NOTHING, если не уверены в последствиях. Это может привести к нарушению целостности данных.
  3. Обратный доступ:

    • Если не указать related_name, Django сгенерирует его автоматически. Но это имя может быть неудобным. Лучше указывать явно:
      author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name="posts")
      
  4. Проблемы с производительностью:

    • Используйте select_related() для оптимизации запросов, если вам нужно получить связанные данные.

Практическое применение

Теперь вы знаете, как организовать связь один-ко-многим с помощью ForeignKey в Django. Этот тип связи — основа большинства веб-приложений, от блогов до систем управления заказами или CRM. Чем больше вы работаете с моделями, тем больше начинаете ценить гибкость и мощь ForeignKey.

1
Задача
Модуль 3: Django, 9 уровень, 2 лекция
Недоступна
Создание моделей со связью один-ко-многим
Создание моделей со связью один-ко-многим
1
Задача
Модуль 3: Django, 9 уровень, 2 лекция
Недоступна
Создание и получение связанных объектов
Создание и получение связанных объектов
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ