Wagtail 4中FieldPanel关联ForeignKey的ID字段错误问题
Wagtail 4.0.4中ForeignKey指定to_field后FieldPanel报错的解决方法
问题场景
你在Wagtail 4.0.4中配置了以下代码:
@register_snippet class Copyright(models.Model): class CopyrightType(models.TextChoices): PH1 = "PH1", _("Phase 1") PH2 = "PH2", _("Phase 2") type = models.CharField( max_length=3, choices=CopyrightType.choices, unique=True, ) class ReportPage(Page): copyright = models.ForeignKey( Copyright, to_field="type", default="PH2", on_delete=models.SET_DEFAULT, )
原本运行正常,但当给ReportPage的promote_panels添加FieldPanel("copyright")后:
class ReportPage(Page): copyright = models.ForeignKey( Copyright, to_field="type", default="PH2", on_delete=models.SET_DEFAULT, ) promote_panels = Page.promote_panels + [ FieldPanel("copyright"), ]
触发了错误:
ValueError: Field 'id' expected a number but got 'PH2'.
解决方法
方法1:使用SnippetChooserPanel(推荐)
因为Copyright是注册的snippet,直接用Wagtail提供的SnippetChooserPanel并指定field_name参数,让它识别你设置的type字段:
from wagtail.snippets.edit_handlers import SnippetChooserPanel class ReportPage(Page): copyright = models.ForeignKey( Copyright, to_field="type", default="PH2", on_delete=models.SET_DEFAULT, ) promote_panels = Page.promote_panels + [ SnippetChooserPanel("copyright", field_name="type"), ]
方法2:自定义ModelChoiceField适配FieldPanel
如果必须使用FieldPanel,可以自定义表单字段,指定to_field_name为type:
from django.forms import ModelChoiceField from wagtail.admin.panels import FieldPanel class CopyrightModelChoiceField(ModelChoiceField): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.to_field_name = "type" class ReportPage(Page): copyright = models.ForeignKey( Copyright, to_field="type", default="PH2", on_delete=models.SET_DEFAULT, ) promote_panels = Page.promote_panels + [ FieldPanel("copyright", widget=CopyrightModelChoiceField(queryset=Copyright.objects.all())), ]
原因说明
Wagtail默认的FieldPanel处理ForeignKey时,会使用Django原生的ModelChoiceField,这个组件默认以主键(id)作为提交的字段值。但你的ForeignKey指定了to_field="type",提交时会传递PH2(type字段的值)去匹配id字段,导致类型不匹配的错误。通过上述方法指定使用type字段作为关联标识,就能解决这个问题。
内容的提问来源于stack exchange,提问作者jcuot
相关产品推荐
相关产品推荐

