用于自引用多对多关系的 Wagtail 面板
Wagtail panel for self-referential many to many relationships with a through model
我正忙着用 wagtail 制作知识图谱之类的东西。
CurriculumContentItem
是该图上的一个节点。和自己是多对多的关系,through模型有重要的字段。
我正在努力让它在管理页面中可用。请参阅内联评论:
class ContentItemOrder(models.Model):
post = models.ForeignKey(
"CurriculumContentItem", on_delete=models.PROTECT, related_name="pre_ordered_content"
)
pre = models.ForeignKey(
"CurriculumContentItem", on_delete=models.PROTECT, related_name="post_ordered_content"
)
hard_requirement = models.BooleanField(default=True)
class CurriculumContentItem(Page):
body = RichTextField(blank=True)
prerequisites = models.ManyToManyField(
"CurriculumContentItem",
related_name="unlocks",
through="ContentItemOrder",
symmetrical=False,
)
content_panels = Page.content_panels + [
# FieldPanel("prerequisites")
# FieldPanel just lets me select CurriculumContentItems, but I need to access fields in the through model
# InlinePanel("prerequisites"),
# This causes a recursion error
FieldPanel('body', classname="full collapsible"),
]
如果我想在普通的 Django 管理中执行此操作,我会使用内联来指定先决条件。类似于:
class ContentItemOrderPostAdmin(admin.TabularInline):
model = models.ContentItem.prerequisites.through
fk_name = "post"
class ContentItemOrderPreAdmin(admin.TabularInline):
model = models.ContentItem.unlocks.through
fk_name = "pre"
Wagtail中有没有类似的机制?
看来我需要为此创建一个自定义面板。
我建议构建一个指向您的 'through' 模型的 InlinePanel,这意味着您正在使用 one-to-many 关系而不是 many-to-many:
class ContentItemOrder(models.Model):
post = ParentalKey(
"CurriculumContentItem", related_name="pre_ordered_content"
)
pre = models.ForeignKey(
"CurriculumContentItem", on_delete=models.PROTECT, related_name="post_ordered_content"
)
hard_requirement = models.BooleanField(default=True)
panels = [
PageChooserPanel('pre'),
FieldPanel('hard_requirement')
]
class CurriculumContentItem(Page):
body = RichTextField(blank=True)
content_panels = Page.content_panels + [
InlinePanel("pre_ordered_content"),
FieldPanel('body', classname="full collapsible"),
]
这个有效:
- 使直通模型继承自Orderable
- 使用
ParentalKey
而不是 ForeignKey
- 使用InlinePanel引用直通模型中字段的相关名称
from modelcluster.fields import ParentalKey
from wagtail.core.models import Page, Orderable
class ContentItemOrder(Orderable): ### 1
post = ParentalKey( ### 2
"CurriculumContentItem", on_delete=models.PROTECT, related_name="pre_ordered_content"
)
pre = ParentalKey( ### 2
"CurriculumContentItem", on_delete=models.PROTECT, related_name="post_ordered_content"
)
hard_requirement = models.BooleanField(default=True)
panels = [
PageChooserPanel('pre'),
PageChooserPanel('post'),
FieldPanel('hard_requirement'),
]
class CurriculumContentItem(Page):
body = RichTextField(blank=True)
prerequisites = models.ManyToManyField(
"CurriculumContentItem",
related_name="unlocks",
through="ContentItemOrder",
symmetrical=False,
)
content_panels = Page.content_panels + [
InlinePanel('pre_ordered_content', label="prerequisites"), ### 3
InlinePanel('post_ordered_content', label="unlocks"), ### 3
FieldPanel('body', classname="full collapsible"),
]
我担心每个内联会有 2 个可用的 PageChooser 字段,但 wagtail 非常聪明(而且神奇),它只绘制我们需要的那个
我正忙着用 wagtail 制作知识图谱之类的东西。
CurriculumContentItem
是该图上的一个节点。和自己是多对多的关系,through模型有重要的字段。
我正在努力让它在管理页面中可用。请参阅内联评论:
class ContentItemOrder(models.Model):
post = models.ForeignKey(
"CurriculumContentItem", on_delete=models.PROTECT, related_name="pre_ordered_content"
)
pre = models.ForeignKey(
"CurriculumContentItem", on_delete=models.PROTECT, related_name="post_ordered_content"
)
hard_requirement = models.BooleanField(default=True)
class CurriculumContentItem(Page):
body = RichTextField(blank=True)
prerequisites = models.ManyToManyField(
"CurriculumContentItem",
related_name="unlocks",
through="ContentItemOrder",
symmetrical=False,
)
content_panels = Page.content_panels + [
# FieldPanel("prerequisites")
# FieldPanel just lets me select CurriculumContentItems, but I need to access fields in the through model
# InlinePanel("prerequisites"),
# This causes a recursion error
FieldPanel('body', classname="full collapsible"),
]
如果我想在普通的 Django 管理中执行此操作,我会使用内联来指定先决条件。类似于:
class ContentItemOrderPostAdmin(admin.TabularInline):
model = models.ContentItem.prerequisites.through
fk_name = "post"
class ContentItemOrderPreAdmin(admin.TabularInline):
model = models.ContentItem.unlocks.through
fk_name = "pre"
Wagtail中有没有类似的机制?
看来我需要为此创建一个自定义面板。
我建议构建一个指向您的 'through' 模型的 InlinePanel,这意味着您正在使用 one-to-many 关系而不是 many-to-many:
class ContentItemOrder(models.Model):
post = ParentalKey(
"CurriculumContentItem", related_name="pre_ordered_content"
)
pre = models.ForeignKey(
"CurriculumContentItem", on_delete=models.PROTECT, related_name="post_ordered_content"
)
hard_requirement = models.BooleanField(default=True)
panels = [
PageChooserPanel('pre'),
FieldPanel('hard_requirement')
]
class CurriculumContentItem(Page):
body = RichTextField(blank=True)
content_panels = Page.content_panels + [
InlinePanel("pre_ordered_content"),
FieldPanel('body', classname="full collapsible"),
]
这个有效:
- 使直通模型继承自Orderable
- 使用
ParentalKey
而不是ForeignKey
- 使用InlinePanel引用直通模型中字段的相关名称
from modelcluster.fields import ParentalKey
from wagtail.core.models import Page, Orderable
class ContentItemOrder(Orderable): ### 1
post = ParentalKey( ### 2
"CurriculumContentItem", on_delete=models.PROTECT, related_name="pre_ordered_content"
)
pre = ParentalKey( ### 2
"CurriculumContentItem", on_delete=models.PROTECT, related_name="post_ordered_content"
)
hard_requirement = models.BooleanField(default=True)
panels = [
PageChooserPanel('pre'),
PageChooserPanel('post'),
FieldPanel('hard_requirement'),
]
class CurriculumContentItem(Page):
body = RichTextField(blank=True)
prerequisites = models.ManyToManyField(
"CurriculumContentItem",
related_name="unlocks",
through="ContentItemOrder",
symmetrical=False,
)
content_panels = Page.content_panels + [
InlinePanel('pre_ordered_content', label="prerequisites"), ### 3
InlinePanel('post_ordered_content', label="unlocks"), ### 3
FieldPanel('body', classname="full collapsible"),
]
我担心每个内联会有 2 个可用的 PageChooser 字段,但 wagtail 非常聪明(而且神奇),它只绘制我们需要的那个