Поле ForeignKey
Поле ForeignKey применяется для установления связи между двумя моделями,
где одной записи родительской модели может соответствовать множество записей
дочерней модели. Поле принимает обязательный аргумент - класс связанной
модели, а также поддерживает дополнительные параметры, такие как
on_delete, определяющий поведение при удалении связанной записи,
related_name для обратной связи и другие. Связи через ForeignKey
позволяют выполнять запросы как от родителя к дочерним записям, так
и в обратную сторону.
Синтаксис
from django.db import models
class ChildModel(models.Model):
parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
Пример
Давайте создадим две модели: Category и Article, где каждая статья
принадлежит одной категории:
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Article(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
category = models.ForeignKey(Category, on_delete=models.CASCADE)
def __str__(self):
return self.title
Пример
Теперь создадим категорию и несколько статей, связанных с этой категорией:
from myapp.models import Category, Article
# Create a category
category = Category.objects.create(name="Programming")
# Create articles belonging to this category
article1 = Article.objects.create(
title="Django Basics",
content="Introduction to Django",
category=category
)
article2 = Article.objects.create(
title="Advanced Django",
content="Deep dive into Django",
category=category
)
print(article1.category.name)
print(article2.category.name)
Результат выполнения кода:
"Programming"
"Programming"
Пример
Получим все статьи, принадлежащие определенной категории, используя обратную связь через менеджер, созданный автоматически:
from myapp.models import Category
category = Category.objects.get(name="Programming")
articles = category.article_set.all()
for article in articles:
print(article.title)
Результат выполнения кода:
"Django Basics"
"Advanced Django"
Пример
Используем параметр related_name для задания более удобного
имени обратной связи:
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=100)
class Article(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
category = models.ForeignKey(
Category,
on_delete=models.CASCADE,
related_name="articles"
)
Теперь обращаться к статьям категории можно через имя articles:
from myapp.models import Category
category = Category.objects.get(name="Programming")
articles = category.articles.all()
for article in articles:
print(article.title)
Результат выполнения кода:
"Django Basics"
"Advanced Django"
Пример
Рассмотрим параметр on_delete, который определяет поведение
при удалении связанного объекта. Используем models.CASCADE
для автоматического удаления всех дочерних записей:
from myapp.models import Category, Article
category = Category.objects.get(name="Programming")
# Delete category - all related articles will be deleted automatically
category.delete()
# Check that articles are deleted
articles_count = Article.objects.filter(category=category).count()
print(articles_count)
Результат выполнения кода:
"0"
Пример
Используем параметр on_delete=models.PROTECT, который запрещает
удаление категории, если к ней привязаны статьи:
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=100)
class Article(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
category = models.ForeignKey(
Category,
on_delete=models.PROTECT
)
При попытке удалить категорию со статьями будет вызвано исключение:
from myapp.models import Category
category = Category.objects.get(name="Programming")
try:
category.delete()
except Exception as e:
print(str(e))
Результат выполнения кода:
"Cannot delete some instances of model 'Category' because they are referenced through protected foreign key"
Смотрите также
-
поле
ManyToManyField,
которое создает связь многие-ко-многим между моделями -
поле
OneToOneField,
которое создает связь один-к-одному между моделями -
метод
select_related,
который оптимизирует запросы с внешними ключами -
метод
prefetch_related,
который оптимизирует запросы с обратными связями