1

我最近添加了一个“通过”模型来允许对连接的对象进行排序。在下面的示例中,Stage 具有通过 StageBlock 链接的有序块列表(使用 StageBlock.order 字段)

@register_snippet
class Block(index.Indexed, models.Model):
    title = models.CharField(max_length=100, verbose_name=_("Block Name"))

@register_snippet
class Stage(index.Indexed, models.Model):
    title = models.CharField(max_length=100, verbose_name=_("Stage Name"))
    blocks = models.ManyToManyField(
        to="app.Block",
        blank=True,
        help_text=_("Blocks associated to this stage"),
        related_name="stages",
        verbose_name=_("Blocks"),
        through="StageBlock",
    )

    panels = [
        FieldPanel("title", classname="title full"),
        FieldPanel(
           "blocks",
           widget=autocomplete.ModelSelect2Multiple(
               url="block-autocomplete",
               attrs={"data-maximum-selection-length": 3},
           ),
        ),



class StageBlock(models.Model):
    block = models.ForeignKey("app.Block", on_delete=models.CASCADE)
    stage = models.ForeignKey("app.Stage", on_delete=models.CASCADE)
    order = models.PositiveSmallIntegerField()

问题是相关的 Wagtail 管理表单中断,因为它试图将 Block 对象关联到 Stage,而不提供“通过”模型“订单”字段值。

我想知道什么是最干净/最省力的解决方案,以允许在管理面板中有序选择元素,然后正确保存 Stage 实例及其块和相关阶段块。

目前,我将在代码片段中添加一个自定义表单,并根据表单数据中块的位置自动分配顺序(希望它始终与在字段面板中选择的块的顺序相匹配)。

感觉这个用例可以通过 wagtail-autocomplete 插件或 wagtail fieldpanel 自动处理。但据我了解,fieldpanel 将简单地重新使用 Django ModelMultipleChoiceField字段,该字段返回一个html元素。

4

1 回答 1

4

与“通过”模型的多对多关系在结构上与该“通过”模型上的一对多子关系在结构上相同,因此一种可能性是使用InlinePanel如此处所述)实现这一点:

from django_modelcluster.fields import ParentalKey
from django_modelcluster.models import ClusterableModel

from wagtail.core.models import Orderable


@register_snippet
class Stage(index.Indexed, ClusterableModel):
    title = models.CharField(max_length=100, verbose_name=_("Stage Name"))

    panels = [
        FieldPanel("title", classname="title full"),
        InlinePanel("blocks", label="Blocks"),
    ]


class StageBlock(Orderable):
    stage = ParentalKey("app.Stage", on_delete=models.CASCADE, related_name='blocks')
    block = models.ForeignKey("app.Block", on_delete=models.CASCADE)

    panels = [
        FieldPanel('block'),
    ]
于 2019-08-08T08:05:43.093 回答