Django - удаление каскада в ManyToManyRelation
Использование следующих связанных моделей (одна запись в блоге может иметь несколько версий):
class BlogEntryRevision(models.Model):
revisionNumber = models.IntegerField()
title = models.CharField(max_length = 120)
text = models.TextField()
[...]
class BlogEntry(models.Model):
revisions = models.ManyToManyField(BlogEntryRevision)
[...]
Как я могу сказать Django удалить все связанные BlogEntryRevision
, когда соответствующий BlogEntry
будет удален? По-умолчанию, по-умолчанию, для объекта, связанного со "другой" стороной, удаляются объекты в отношении "многие-ко-многим". Любой способ сделать это - желательно без переопределения BlogEntry.delete
?
Ответы
Ответ 1
Я думаю, что вы неправильно понимаете природу отношений ManyToMany. Вы говорите о том, что "соответствующий BlogEntry" был удален. Но весь смысл ManyToMany заключается в том, что каждый BlogEntryRevision имеет несколько связанных с ним BlogEntries. (И, конечно, у каждого BlogEntry есть несколько BlogEntryRevisions, но вы уже это знаете.)
Исходя из названий, которые вы использовали, и того факта, что вам нужна эта каскадная функция удаления, я думаю, вам лучше использовать стандартный ключ ForeignKey от BlogEntryRevision до BlogEntry. Пока вы не установите null=True
для этого ForeignKey, удаления будут каскадно - когда удаляется BlogEntry, все ревизии будут тоже.
Начиная с версии Django 2.0
Инициализатор ForeignKey
теперь требует, чтобы вы указали параметр on_delete
:
from django.db import models
from .models import MyRelatedModel
class model(models.Model):
related_model = models.ForeignKey(MyRelatedModel, on_delete=models.CASCADE)
Ответ 2
У меня был точный вариант использования сегодня:
- Автор модели: может иметь несколько записей
- Модель входа: может иметь несколько авторов
Для этого я использую ManyToManyRelationship.
Мой вариант использования был: если я удалю последнюю запись определенного автора, то этот автор также должен быть удален.
Решение может быть достигнуто с помощью сигнала pre_delete
:
@receiver(pre_delete, sender=Entry)
def pre_delete_story(sender, instance, **kwargs):
for author in instance.authors.all():
if author.entries.count() == 1 and instance in author.entries.all():
# instance is the only Entry authored by this Author, so delete it
author.delete()
Ответ 3
Вы можете использовать пользовательский диспетчер моделей, но документация, похоже, указывает, что она делает что-то подобное уже, и я не могу точно вспомнить, что это значит:
Метод удаления, удобно, named delete(). Этот метод немедленно удаляет объект и нет возвращаемого значения. Пример:
e.delete()
Вы также можете удалить объекты оптом. Каждый QuerySet имеет delete() метод, который удаляет всех членов что QuerySet.
Например, это удаляет всю запись объекты с pub_date 2005 года:
Entry.objects.filter(pub_date__year=2005).delete()
Имейте в виду, что это будет, когда возможно, выполняться исключительно в SQL, и поэтому методы delete() экземпляры отдельных объектов не будут обязательно должны быть вызваны во время обработать. Если вы предоставили заказ delete() в классе модели и хотите, чтобы он был вызван, вы необходимо "вручную" удалить экземпляров этой модели (например, итерация по QuerySet и вызов delete() для каждого объекта отдельно) вместо использования объемного удаления() метод QuerySet.
Когда Django удаляет объект, он эмулирует поведение SQL ограничение УДАЛИТЬ КАСКАД - в другими словами, любые объекты, которые внешние ключи, указывающие на объект будут удалены вместе с это. Например:
b = Blog.objects.get(pk=1)
# This will delete the Blog and all of its Entry objects.
b.delete()
Ответ 4
Просто используйте метод clear()
для удаления связанных объектов, поскольку Django использует сквозную модель для определения отношений, которые метод clear удаляет все связанные BlogEntryRevision
be = BlogEntry.objects.get(id=1)
be.blogentryrevision_set.clear()