如何在使用Wagtail admin创建页面时以编程方式选择父级?

2024-04-29 04:49:58 发布

您现在位置:Python中文网/ 问答频道 /正文

我有两个模型,其中一个是另一个的索引页:

class FooIndexPage(Page):
    category = models.IntegerField(unique=True)
    subpage_types = ['foo.fooPage']

class FooPage(Page):
    category = models.IntegerField()

我显然漏掉了大部分字段,因为它们与我的问题无关。FooPagecategory字段实际上是从其他字段派生的;我这么说只是为了简单

我想要实现的是:每个FooPage最终都应该是树结构中某个FooIndexPage的子级。但是,在创建页面之前,还不清楚哪个页面是正确的FooIndexPage(因为category是从其他字段派生的,如上所述)。还有一种可能性是,它还不存在,必须首先创建。当用户创建FooPage(用户在管理界面中将页面创建为主页的子页面)时,整个过程应该会自动发生。用户保存页面后,应将其移动到相应的FooIndexPage,可能必须首先创建该页面

我试图通过重写FooPagesave方法并在创建后相应地移动页面来解决此问题:

def save(self, *args, **kwargs):
    super().save(*args, **kwargs)
    category = self.category
    if not FooIndexPage.objects.filter(category=category).exists():
        self.get_parent().add_child(instance=FooIndexPage(category=category))
    index_page = FooIndexPage.objects.get(category=category)
    self.move(index_page, 'last-child')

如果正确的FooIndexPage不存在,则创建它。但是,该代码在self.move上引发了一个异常:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/.../lib/python3.8/site-packages/wagtail/core/models.py", line 1381, in move
    super().move(target, pos=pos)
  File "/home/.../lib/python3.8/site-packages/treebeard/mp_tree.py", line 1095, in move
    return MP_MoveHandler(self, target, pos).process()
  File "/home/.../lib/python3.8/site-packages/treebeard/mp_tree.py", line 472, in process
    if self.target.is_descendant_of(self.node):
AttributeError: 'NoneType' object has no attribute 'is_descendant_of'

这似乎是treebeard的一个已知问题,它发生在父页面还没有子页面时。不过,我没能找到解决办法

创建页面时是否有方法覆盖父页面?


Tags: 用户inselfhomemovemodelssavelib
1条回答
网友
1楼 · 发布于 2024-04-29 04:49:58

根据the Treebeard docs

django-treebeard uses Django raw SQL queries for some write operations, and raw queries don’t update the objects in the ORM since it’s being bypassed.

Because of this, if you have a node in memory and plan to use it after a tree modification (adding/removing/moving nodes), you need to reload it.

通过创建index_page,可以在节点self仍在内存中时修改树。很难知道这可能会导致什么类型的问题,但是如果例如创建索引页导致selfpath值发生更改,那么move操作可能会基于过时的path值执行更新。此时可能值得运行./manage.py fixtree,以检查树结构是否发生任何损坏

在移动之前运行self.refresh_from_db()应该可以避免这种情况,但我并不100%相信在save方法中这样做是安全的,因此我倾向于通过获取self节点的新副本并在该节点上运行move来避免这种情况:

new_self = Page.objects.get(pk=self.pk)
new_self.move(index_page, 'last-child')

相关问题 更多 >