#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, но я не могу его установить.