【问题标题】:Moving Wagtail pages in a migration在迁移中移动 Wagtail 页面
【发布时间】:2018-03-17 13:52:42
【问题描述】:

我正在重组我的 Wagtail 应用程序以删除其中只有一个项目的 IndexPage,并将该项目移动为当前 IndexPage 父项的子项。

基本上是从这个开始的:

Page--| |--IndexPage--| |--ChildPages(只有 1 个)

到这里:

Page--| |--ChildPage

我已经对模型进行了更改,以便此结构用于创建新内容,并将相关视图固定为直接指向 ChildPage。但是现在我想将当前数据迁移到新结构中,但我不确定如何去做……理想情况下,这将在迁移中完成,这样我们就不必手动进行任何操作。

有没有办法在迁移期间以编程方式将这些 ChildPage 向上移动?

【问题讨论】:

    标签: django-migrations wagtail


    【解决方案1】:

    不幸的是,有一个硬性限制(可能)排除了在迁移中进行页面树调整的可能性:诸如插入、移动和删除页面之类的树操作是作为 Page 模型上的方法实现的,并且在迁移中您只能访问该模型的“虚拟”版本,它只能让您访问数据库字段和基本 ORM 方法,而不是那些自定义方法。

    (您可以通过将from wagtail.wagtailcore.models import Page 放入迁移中并使用它而不是标准的Page = apps.get_model("wagtailcore", "Page") 方法来解决此问题,但我不建议这样做 - 如果迁移运行在Page 模型仍在构建中且与模型的“真实”状态不匹配的迁移序列中的一个点。)

    相反,我建议编写 Django management command 来进行树操作 - 在管理命令中,从 wagtailcore 以及您的特定页面导入 Page 模型是安全的楷模。 Page 提供了一个方法 move(target, pos) 可以工作 as per the Treebeard API - 移动子页面的代码可能类似于:

    from myapp.models import IndexPage
    
    # ...
    for index_page in IndexPage.objects.all():
        for child_page in index_page.get_children():
            child_page.move(index_page, 'right')
        index_page.delete()
    

    【讨论】:

    • 这有点像我想的......我在迁移中实现了get_parent()get_children()方法,但在实现move()时我放弃了操作,相当复杂。
    【解决方案2】:

    理论上,应该可以使用 Daniele Miele 在Django-treebeard and Wagtail page creation 中演示的相同类型的操作来构建 move()。它看起来像这样的 Python 伪代码:

    def move(page, target):
      # assuming pos='last_child' but other cases follow similarly,
      # just with more bookkeeping
    
      # first, cut it out of its old tree
      page.parent.numchild -= 1
      for sib in page.right_siblings: # i.e. those with a greater path
        old = sib.path
        new = sib.path[:-4] + (int(sib.path[-4:])-1):04
        sib.path = new
        for nib in sib.descendants:
          nib.path = nib.path.replace_prefix(old, new)
      
      # now, update itself
      old_path = page.path
      new_path = target.path + (target.numchild+1):04
      page.path = new_path
      old_url_path = page.url_path
      new_url_path = target.url_path + page.url_path.last
      page.url_path = new_url_path
      old_depth = page.depth
      new_depth = target.depth + 1
      page.depth = new_depth
    
      # and its descendants
      depth_change = new_depth - old_depth
      for descendant in page.descendants:
        descendant.path = descendant.path.replace_prefix(old_path, new_path)
        descendant.url_path = descendant.url_path.replace_prefix(old_path, new_path)
        descendant.depth += depth_change
    
      # finally, update its new parent
      target.numchild += 1
    

    使这种操作比看起来更简单的核心概念是:当一个节点被重新排序或移动时,它的所有后代都需要更新,只有更新他们需要的是他们祖先得到的完全相同的更新。它被用作前缀替换(如果是 str)或差异(如果是 int),两者都不需要知道后代的确切值。

    也就是说,我还没有测试过;它足够复杂,很容易搞砸;并且无法知道我是否更新了 Wagtail 关心的每个不变量。所以管理指挥方式也有话要说。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-10-28
      • 1970-01-01
      • 1970-01-01
      • 2014-04-08
      • 1970-01-01
      • 2012-07-14
      • 1970-01-01
      相关资源
      最近更新 更多