Каскадное удаление в Django + сбор удаленных данных

У меня есть модели Django 2.2:

class A(models.Model):
    pass

class B(models.Model):
    a = models.ForeignKey(A, on_delete=models.CASCADE)

class C(models.Model):
    b = models.ForeignKey(B, on_delete=models.CASCADE)
    url = models.URLField(...)

def do_something(set_of_urls):
    ...

What I want is to do_something with all url values for which C instance being deleted, but I need to do it at once.

In other words, when a.delete() cascades, deleting all of its B children, which in turn delete all of their C children, I want to call

do_something({c.url for c in C.objects.filter(b__a_id=a.pk)})

Но я также хочу иметь возможность сделать b.delete(), что в результате приведет к

do_something({c.url for c in C.objects.filter(b_id=b.pk)})

And same for c.delete() (which would just do do_something({c.url})).

Далее, удаление менеджеров отношений должно вести себя аналогичным образом:

  1. A.objects.filter(...).delete() would ideally call do_something for each deleted instance of A (so, not all URLs at once, but one call per each delete object). If grouping is problematic to implement, I could do with do_something for URLs of all affected instances of C. But I must avoid calling do_something for each affected C-child separately.

  2. B.objects.filter(...). delete() would call do_something for all URLs belonging to children of those deleted instances (filter will always ensure that all deleted instances of B belong to the same instance of A, so no grouping is needed).

  3. C.objects.filter(...).delete() would call do_something for all URLs belonging to deleted instances (again, no grouping is needed).

I thought of using pre_delete or post_delete signals, but these seem to work bottom-up, meaning that individual processing of URLs in grandchildren of a will be done before we get to pre_delete of A, which means that do_something would get called by each C-grandchild of a instead of all of them in bulk.

Есть ли хороший способ сделать это?

Побочный вопрос для комментариев: документирован ли порядок вызовов сигналов в случае каскадного удаления где-нибудь в документации Django или где-нибудь еще? Я не смог его найти.

Вернуться на верх