Перебирать кучу содержимого папок, которое само может быть папочным?

#python #recursion #plone

#python #рекурсия #plone

Вопрос:

Предположим, у меня есть тип содержимого, папка, с 4 элементами.

   MyObject
 - Child1
 - Child2
 - Child3
   Child4
  - Child5
 - Child6
  

Предположим, у меня есть другой тип содержимого (давайте назовем его Alias ). Это Alias в основном ссылка на другой объект, но не папочный: он может содержать кучу других псевдонимов. Я собираюсь использовать --> для указания этой ссылки в следующих древовидных представлениях.(«Ссылка» — это в основном атрибут, называемый «reference», который получает UID от целевого объекта).

Предположим, MyAlias теперь ссылается на мой MyObject .

   MyAlias --> MyObject
 - (Nothing)
  

При ссылке на MyObject , MyAlias не знает, что MyObject это папка, поэтому внутренние дочерние элементы MyAlias не существуют. Мне нужно перебрать все и создать вручную псевдоним внутри MyAlias , который является ссылкой (имеющей ту же структуру) на MyObject дочерние элементы. Небольшое дерево, показывающее, что должно произойти:

   MyAlias --> MyObject
 - Alias --> Child1
 - Alias --> Child2
 - Alias --> Child3
   Alias --> Child4
  - Alias --> Child5
 - Alias --> Child6
  

Я хотел бы знать лучший способ перебирать MyObject элементы и создавать ту же структуру с другими объектами, используя какой-то цикл и используя invokeFactory в подписчике. В итоге у меня были бы ОБА существующих дерева: одно из фактической папки и дочерних элементов, а другое из ссылок на эту же папку и дочерние элементы.

(Подводя итог: что-то вроде collective.alias, но в действительно примитивной форме, просто папки с документами, поскольку я не могу использовать collective.alias.)

Комментарии:

1. Почему бы не использовать portal_catalog? Это ваш друг, он легко предоставит вам все объекты по вашему текущему пути и глубже!

2. @Martijn Pieters: Я обновил свой вопрос, добавив больше информации о сценарии.

3. @Somebody: Я все еще не вижу причин не использовать каталог! 🙂

4. @Somebody: каталог также мгновенно предоставляет вам список всех дочерних элементов; отсортируйте эти результаты по пути, и у вас будет отсортирован по глубине список текущего контекста и всех его потомков. Смотрите ответ @ggozad ниже.

5. @Somebody: Если вы пойдете этим путем, вы можете получить локальные дочерние элементы объекта folderish, вызвав .contentIds() . Но если вашему объекту псевдонима нужен только путь или UID исходного объекта, нет необходимости загружать все дерево в память, каталог также предоставляет вам эту информацию.

Ответ №1:

Самое элегантное и питоновское решение — написать рекурсивный генератор. Предполагая, что это метод:

 def iter_preorder(self):
    yield self
    # check for folderishness here if a non-folderish
    # node may have children as well
    for x in self.children:
        for y in x.iter_preorder():
            yield y
  

Затем

 for x in tree.iter_preorder():
    do_action(x)
  

Таким образом, вам на самом деле не нужно переносить свое действие в функцию / вызываемый объект, и нет инверсии управления.

Комментарии:

1. Это не совсем Plone, но я использовал этот подход, когда у меня уже был родительский объект, который мне был нужен на подписчике. if target.isPrincipiaFolderish: for child in target.objectValues(): .

Ответ №2:

Рекурсивность может помочь

 def do_action(child):
    if child.isfolder():
        for i in child:
            do_action(i)
    else:
        child.setSomething()

do_action(MyObject)
  

Ответ №3:

Почему бы вам не использовать каталог? Каталог существует для быстрого и безопасного решения этих проблем для вас, чтобы вы могли сосредоточиться на важных вещах. Итак, чтобы найти все объекты по некоторому пути:

 ct = getToolByName(context, 'portal_catalog')
path = '/'.join(context.getPhysicalPath())
brains = ct.searchResults(path=path)
  

Вы, конечно, можете отфильтровать больше в своем запросе. Затем,

 for brain in brains:
    obj = brain.getObject()
    obj.setSomething()
  

Каталог — ваш друг, прочитайте, как им пользоваться.

Комментарии:

1. Настоящая проблема заключается в рекурсивности. Я все еще могу использовать каталог, но мне нужно зациклить все объекты и всех их дочерних элементов. Но вместо того, чтобы использовать решение @Martijn Pieters .contentIds() , я собираюсь использовать .objectValues() .

Ответ №4:

Похоже, вы пытаетесь выполнить миграцию типа контента. Если это так, взгляните на Products.contentmigration.

Комментарии:

1. Спасибо за предложение, но это не миграция, поскольку оба содержимого должны существовать. Мне нужно иметь что-то похожее на collective.alias, но я не могу его установить.