Django-mptt использует get_root() для элемента TreeQuerySet внутри цикла for, и выходные данные, сохраненные в списке, не сохраняются за пределами цикла for

Я пытаюсь использовать get_root() для отдельных элементов TreeQuerySet в цикле for. Кажется, это работает в оболочке Django Python, как показано ниже. При двойном нажатии [Enter] для обозначения окончания цикла for результат применения get_root() к каждому элементу автоматически выводится на экран командной строки. Результат верен в том смысле, что в выходных данных действительно указан корень верхнего уровня каждого элемента TreeQuerySet.

Однако вне цикла список, в котором они должны храниться, не обновляется. Вместо этого этот список содержит исходные элементы TreeQuerySet.


In Django Python shell:
>>> topics_w_arttype_articles = topics.Topic.objects.filter(to_ArtTypeArticle_topic_from_Topic__title__isnull=False).distinct()
>>> topics_w_arttype_articles
<TreeQuerySet [<Topic: Level1Topic1>, <Topic: Level1Topic2>, <Topic: Level1Topic3>, <Topic: Level1Topic4>, <Topic: Level2Topic1>, <Topic: Level2Topic2>, <Topic: Level2Topic3>, <Topic: Level2Topic4>]>
>>> arttype_topic_roots_list = []
>>> for item in topics_w_arttype_articles.iterator():
...     item.get_root()
...     arttype_topic_roots_list.append(item)
...
<Topic: Level0Topic1>
<Topic: Level0Topic2>
<Topic: Level0Topic2>
<Topic: Level0Topic3>
<Topic: Level0Topic4>
<Topic: Level0Topic5>
<Topic: Level0Topic5>
<Topic: Level0Topic5>
>>> arttype_topic_roots_list
[<Topic: Level1Topic1>, <Topic: Level1Topic2>, <Topic: Level1Topic3>, <Topic: Level1Topic4>, <Topic: Level2Topic1>, <Topic: Level2Topic2>, <Topic: Level2Topic3>, <Topic: Level2Topic4>]
>>>

Я поместил логику взаимодействия с оболочкой в пользовательский тег шаблона, показанный ниже (с дополнительным кодом, который должен удалять дубликаты из списка, если они сохранялись вне цикла), чтобы предоставить список шаблонам. При использовании в шаблоне элементами являются исходные элементы TreeQuerySet, а не корневые узлы, созданные в цикле for. В чем проблема?

@register.simple_tag
def get_topic_roots_warticles():

    topics_w_arttype_articles = topics.Topic.objects.filter(to_ArtTypeArticle_topic_from_Topic__title__isnull=False).distinct()
    #topics_w_arttype_articles_list = list(topics_w_arttype_articles)

    arttype_topic_roots_list = []
    for item in topics_w_arttype_articles:
        item.get_root()
        arttype_topic_roots_list.append(item)

    arttype_topic_roots_list_unique = []
    for val in arttype_topic_roots_list:
        if val not in arttype_topic_roots_list_unique:
            arttype_topic_roots_list_unique.append(val)

    return arttype_topic_roots_list_unique

В случае, если это имеет значение, соответствующая модель статьи выглядит следующим образом:

class ArtTypeArticle(articles.models.Article):

    topic = TreeManyToManyField(
        Topic,
        related_name = 'to_ArtTypeArticle_topic_from_Topic',
        blank=True,
        )

    def __str__(self):
        """
        String for representing the Model object.
        """
        return self.title # defined in articles.models.Article

И тема модели MPTT такова:

class Topic(MPTTModel):
    name = models.CharField(max_length=100)
    parent = TreeForeignKey(
        'self',
        related_name='return_to_Topic_parent_from_self',
        on_delete=models.SET_NULL,
        null=True,
        blank=True)
    description = models.TextField(
        max_length=1000,
        default='',
        null=True,
        blank=True)

    class MPTTMeta:
        order_insertion_by = ['name']

    class Meta:
        verbose_name = 'Topic'
        verbose_name_plural = 'Topics'

    def __str__(self):
        return self.name

    def get_first_ancestor(self):

        if (self.level >= 1):
            topic_object_first_ancestor = self.get_ancestors(ascending=True, include_self=False)[0]
            return topic_object_first_ancestor

    def get_second_ancestor(self):

        if (self.level >=2):
            topic_object_second_ancestor = self.get_ancestors(ascending=True, include_self=False)[1]
            return topic_object_second_ancestor

    def get_all_descendants(self):

        topic_object_all_descendants = self.get_descendants(include_self=False)
        return topic_object_all_descendants

Я пробовал заменить TreeQuerySet в списке на list() и использовать этот список в качестве элементов в цикле for. Это не имеет никакого значения.

Я также пробовал заменить item.get_root() на item.first().get_root, но это приводит к ошибке, подобной "first не является атрибутом объекта".

Я ожидал, что в оболочке >>> arttype_topic_roots_list будет создан список категорий Level0, как внутри цикла for, т.е.

<Topic: Level0Topic1>
<Topic: Level0Topic2>
<Topic: Level0Topic2>
<Topic: Level0Topic3>
<Topic: Level0Topic4>
<Topic: Level0Topic5>
<Topic: Level0Topic5>
<Topic: Level0Topic5>

а не:

>>> arttype_topic_roots_list
[<Topic: Level1Topic1>, <Topic: Level1Topic2>, <Topic: Level1Topic3>, <Topic: Level1Topic4>, <Topic: Level2Topic1>, <Topic: Level2Topic2>, <Topic: Level2Topic3>, <Topic: Level2Topic4>]

В шаблоне я ожидал, что будут доступны корни верхнего уровня, а не исходные элементы TreeQuerySet.

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