Подтвердить что ты не робот

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?

4b9b3361

Ответ 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()