Совет по добавлению предков ArrayField в самореферентную модель в Django

Я разрабатываю приложение Django (Django 3.2.8, Python 3.9, PostgreSQL 13.4), которое функционирует очень похоже на FTP-сервис. Для структуры папок/файлов я создал самореферентную модель под названием "Instance", которая также использует общие отношения, чтобы я мог повторно использовать/структурировать различные типы контента друг под друга:

class Instance(models.Model):
    parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
    subscribers = models.ManyToManyField('users.Organization', blank=True)
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

Однако, я обнаружил, что разработка ограничивается/замедляется из-за необходимости выполнения необработанных CTE-запросов. И я думаю, что наиболее элегантный способ (основанный на представлениях, которые мне нужны) сделать эту модель полностью доступной для ORM - это добавить "предков" ArrayField.

class Instance(models.Model):
    parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
    ancestors = ArrayField(models.PositiveIntegerField(), null=True, blank=True, default=list)
    ....

Я легко смог создать & добавить значение массива в это поле через мои представления/скрипты с помощью функции типа:

def get_ancestors(context_instance, ancestors_array):
    ancestors_array.append(context_instance.id)
    if context_instance.parent:
        return get_ancestors(context_instance.parent, ancestors_array)
    else:
        return list(reversed(ancestors_array))

Однако я подумал, что было бы гораздо лучше, если бы значение массива предков вычислялось и добавлялось каждый раз, когда сохраняется экземпляр модели "Instance" .

Я не мог понять, как можно запросить экземпляры модели из самого определения модели. Но я рад сообщить, что подход, основанный на этом ответе и ответе по ссылке выше, действительно сработал. Вот мой код:

class Instance(models.Model):
    parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
    ancestors = ArrayField(models.PositiveIntegerField(), null=True, blank=True, default=list)
    subscribers = models.ManyToManyField('users.Organization', blank=True)
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

    @property
    def get_ancestors(instance):
        ancestors_array = []
        while instance.parent:
            ancestors_array.append(instance.parent.id)
            instance = instance.parent
        return list(reversed(ancestors_array))

    def save(self, *args, **kwargs):
        self.ancestors = self.get_ancestors
        super(Instance, self).save(*args, **kwargs)

Прежде чем я продолжу свой веселый путь, может ли кто-нибудь сказать мне, может ли такой подход быть чреват опасностью, или мой процесс размышлений в чем-то ошибочен? Я относительно новичок в Python & Django и мне еще многому предстоит научиться. Спасибо.

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