Django действительно эмулирует поведение SQL ON DELETE CASCADE
, и не существует готового документированного способа изменить это. Документы, в которых они упоминают об этом, находятся в конце этого раздела: Удаление объектов .
Вы правы, что Django собирает все связанные экземпляры модели, а затем вызывает обработчик предварительного удаления для каждого. Отправителем сигнала будет класс модели, который должен быть удален, в данном случае Message
, а не User
, что затрудняет обнаружение разницы между каскадным удалением, инициированным пользователем, и обычным удалением ... тем более, что сигнал на удаление класса User приходит последним, поскольку это последнее удаление: -)
Однако вы можете получить список объектов, которые Django предлагает удалить до вызова функции User.delete (). Каждый экземпляр модели имеет полуприватный метод с именем _collect_sub_objects()
, который компилирует список экземпляров с указанием внешних ключей (он компилирует этот список без удаления экземпляров). Вы можете увидеть, как этот метод вызывается, взглянув на delete()
в django.db.base
.
Если бы это был один из ваших собственных объектов, я бы рекомендовал переопределить метод delete()
в вашем экземпляре, чтобы запустить _collect_sub_objects (), а затем разбить ForeignKeys перед вызовом удаления суперкласса. Поскольку вы используете встроенный объект Django, который может оказаться слишком сложным для подкласса (хотя можно заменить собственный объект User на объект django), вам, возможно, придется полагаться на логику представления для запуска _collect_sub_objects
и прерывания ФК перед удалением.
Вот быстрый пример:
from django.db.models.query import CollectedObjects
u = User.objects.get(id=1)
instances_to_be_deleted = CollectedObjects()
u._collect_sub_objects(instances_to_be_deleted)
for k in instances_to_be_deleted.ordered_keys():
inst_dict = instances_to_be_deleted.data[k]
for i in inst_dict.values():
i.sender = None # You will need a more generic way for this
i.save()
u.delete()