Совет по добавлению предков 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 и мне еще многому предстоит научиться. Спасибо.