RestrictedError

Исключение RestrictedError выбрасывается при попытке удаления объекта модели, который защищён через внешний ключ с параметром on_delete=models.PROTECT. Это исключение является подклассом IntegrityError и используется для предотвращения случайного удаления данных, на которые есть зависимости в других таблицах. Оно возникает только в том случае, когда существуют связанные записи, ссылающиеся на удаляемый объект.

Синтаксис

pythonfrom django.db.models.deletion import RestrictedError

try:
    obj.delete()
except RestrictedError as e:
    # Обработка ошибки
    print(e)

Пример . Модель

Рассмотрим модели Category и Article, где категория защищена от удаления, если на неё ссылаются статьи:

pythonfrom 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)
    category = models.ForeignKey(
        Category,
        on_delete=models.PROTECT,
        related_name='articles'
    )
    
    def __str__(self):
        return self.title

Пример . Возникновение исключения

Попробуем удалить категорию, которая содержит связанные статьи:

pythonfrom myapp.models import Category, Article

# Создаём категорию и статью
category = Category.objects.create(name='Technology')
Article.objects.create(title='Django Basics', category=category)

# Пытаемся удалить категорию
try:
    category.delete()
except RestrictedError as e:
    print(f"Error: {e}")

Результат выполнения кода:

python"Error: Cannot delete category 'Technology' because it has protected related objects: Article: Django Basics"

Обработка исключения с получением связанных объектов

Исключение RestrictedError содержит информацию о защищённых объектах, которые мешают удалению:

pythonfrom myapp.models import Category, Article

category = Category.objects.get(name='Technology')

try:
    category.delete()
except RestrictedError as e:
    # Получаем защищённые объекты
    protected_objects = e.protected_objects
    print(f"Protected objects: {protected_objects}")
    
    # Можно вывести информацию о каждом объекте
    for obj in protected_objects:
        print(f" - {obj}")

Результат выполнения кода:

python"Protected objects: [<Article: Django Basics>]"
" - Django Basics"

Обход исключения через каскадное удаление

Если необходимо удалить категорию вместе со всеми статьями, нужно изменить параметр on_delete на models.CASCADE:

pythonfrom django.db import models

class Category(models.Model):
    name = models.CharField(max_length=100)

class Article(models.Model):
    title = models.CharField(max_length=200)
    category = models.ForeignKey(
        Category,
        on_delete=models.CASCADE,
        related_name='articles'
    )

Теперь удаление категории будет удалять все связанные статьи:

pythonfrom myapp.models import Category, Article

category = Category.objects.get(name='Technology')

# Удаляем категорию со всеми статьями
deleted_count = category.delete()
print(f"Deleted {deleted_count} objects")

Результат выполнения кода:

python"Deleted (2, {'myapp.Article': 1, 'myapp.Category': 1})"

Смотрите также

  • исключение ProtectedError,
    которое возникает при попытке удалить объект с защищёнными связями
  • исключение IntegrityError,
    базовое исключение для ошибок целостности базы данных
  • исключение DoesNotExist,
    которое возникает при отсутствии запрашиваемого объекта
  • исключение ObjectDoesNotExist,
    базовое исключение для всех DoesNotExist ошибок моделей