Как обратиться ко всем дочерним объектам с помощью существующих запросов в самоссылающемся внешнем ключе?

У меня есть модель, которая представляет владельца. В этой модели есть внешний ключ к самому себе, чтобы представить родительскую сущность. Есть еще одна модель под названием актив с внешним ключом на владельца. Цель внешнего ключа родителя - эмулировать корпоративную структуру, такую, что родитель "владеет" активом, внешним ключом которого является он сам или дочерняя компания:

Class Owner(models.Model):
    parent = models.ForeignKey(
                 “self”,
             )

Class Asset(models.Model):
    owner = models.ForeignKey(
                 Owner,
             )

Есть ли способ вернуть все активы, принадлежащие материнской компании и всем ее дочерним компаниям, просто сославшись на родительскую компанию (например, Asset.object.filter(owner=parent))? Я знаю, что могу создать метод для возврата кверисета всех дочерних компаний родителя, а затем отфильтровать все активы в этом кверисете по владельцу, но я надеюсь избежать большого рефакторинга, учитывая, что в существующей кодовой базе нет понятия владельца родителя.

Моя первая мысль - пользовательский менеджер, но я не думаю, что это изменит поведение существующих запросов, которые все работают с менеджером по умолчанию. Могу ли я перегрузить фильтр на этой модели? Если мне нужно переосмыслить дизайн, это хорошо, но я думаю, что этот подход чище и передает поведение, которое мы хотим. Спасибо!

Возможно, это неудовлетворительный или неполный ответ, но у меня есть необработанный запрос postgres, который возвращает всех детей для родителя в одном запросе. В нем используется рекурсивный запрос

class Owner(models.Model):
    parent = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True)

    def get_all_children(self):
        return Owner.objects.raw(f"""
            with recursive t(id, parent_id) as
            (
                select id, parent_id
                from app_owner where id={self.id}
                union all
                select b.id, b.parent_id
                from app_owner b
                join t on b.parent_id=t.id
            )
            select * from t
        """)

Это можно использовать и для фильтрации активов

Asset.objects.filter(owner__in=Owner.objects.get(id=1).get_all_children())
Вернуться на верх