我可以在 Wagtail 中使用递归的 ParentalKey 吗?

Can I use a recursive ParentalKey in Wagtail?

假设我在 Wagtail 应用程序中有以下模型:

# models.py
from django.db import models
from django.db.models.deletion import CASCADE

from wagtail.admin.edit_handlers import InlinePanel, FieldPanel

from modelcluster.models import ParentalKey, ClusterableModel


class Person(ClusterableModel):
    name = models.CharField(max_length=300)
    contact_for = ParentalKey(
        'self', on_delete=CASCADE, null=True, related_name='contacts'
    )

    panels = [
        FieldPanel('name'),
        FieldPanel('contact_for'),
        InlinePanel('contacts')
    ]

以及以下挂钩:

# wagtail_hooks.py
from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register
from home.models import Person


class PersonAdmin(ModelAdmin):
    model = Person
    menu_label = 'People'
    menu_icon = 'list-ul'
    menu_order = 200
    add_to_settings_menu = False
    exclude_from_explorer = False
    list_display = ('name',)
    search_fields = ('name',)
    list_filter = ('contact_for',)


modeladmin_register(PersonAdmin)

当 运行 执行上述操作并导航到“管理”>“人员”>“添加人员”时,我将收到 RecursionError 异常(超出最大递归深度)。

我猜这是一个与 Wagtail 相关的问题,因为我可以按照 IPython:

中的预期使用 class
./manage.py shell -i ipython

In [1]: from home.models import Person

In [2]: mike = Person(name='Mike')

In [3]: mike.contacts = [Person(name='Sam'), Person(name='John')]

In [4]: mike.contacts
Out[4]: <modelcluster.fields.create_deferring_foreign_related_manager.<locals>.DeferringRelatedManager at 0x7f36e9548af0>

In [5]: mike.save()

In [6]: [person.name for person in Person.objects.all()]
Out[6]: ['Mike', 'Sam', 'John']

In [7]: Person.objects.all()[1].contact_for.name
Out[7]: 'Mike'

那么,有没有办法在 Wagtail 中使用递归 ParentalKey?我在做什么 wrong/missing?

编辑:我刚找到 。所以我想知道我是否应该为非页面模型尝试使用 ParentalKey(和 ParentalManyToManyField)。

编辑 2:对于任何感兴趣的人,我最终拆分了我的模型以避免递归键。 InlinePanels 与 ModelAdmin classes 一起工作,只是 Wagtail 似乎 不支持递归键。我还选择在合适的地方使用 Snippets 和 SnippetChooserPanel。

ParentalKey 意味着子模型在概念上被视为 'part of' 父模型并且不作为独立实体存在 - 例如,图片库是页面的一部分 - 用于诸如版本控制和审核工作流程。 (在Wagtail中,通过snippets或ModelAdmin处理的非页面模型不具备这些特性,但为了让它们与页面共享相同的InlinePanel机制,它们也使用了ParentalKey。)

在这种情况下,Person 不是另一个 Person 的一部分,需要独立于 'parent' 进行编辑,因此 ParentalKey 在这里不合适。相反,您应该使用 ForeignKey,它仅指示模型之间的某种关系。这确实意味着您不能使用 InlinePanel 来管理同一视图中的多个 Person 记录 - 您必须分别编辑它们,并使用 SnippetChooserPanel 之类的东西或简单的下拉菜单来设置它们之间的关系。