如何更改 Wagtail 的表单生成器呈现的 <textarea> 中的行数

How to change number of rows in a <textarea> rendered by Wagtail's form builder

我使用 Wagtail 的表单生成器创建了一个表单,其中包含一个多行文本项。当呈现 <textarea> 元素时,它会呈现 rows="10"。我需要减少行数,但在文档中没有看到任何有关如何执行此操作的信息。

快速解决方案

  • 创建一个 class 从 wagtail.contrib.forms.forms
  • 扩展 FormBuilder
  • 在此CustomFormBuilderclass重写方法create_multiline_field
  • 这个方法应该return一个Django Form Field
  • 默认使用的小部件是 Textarea and the default html attrs 列数:40 行数:10
  • 在覆盖的方法中,传入您需要的任何自定义属性,例如attrs = {'cols': '20', 'rows': '20'}
  • 最后,确保您的 FormPage 已将 form_builder 设置为 CustomFormBuilder class。
  • 下面的完整代码片段,这将使所有多行表单字段相同
from django.db import models
import django.forms

from modelcluster.fields import ParentalKey

from wagtail.contrib.forms.forms import FormBuilder
from wagtail.contrib.forms.models import AbstractEmailForm, AbstractFormField
from wagtail.admin.edit_handlers import FieldPanel, FieldRowPanel, InlinePanel, MultiFieldPanel


class FormField(AbstractFormField):
    page = ParentalKey('FormPage', related_name='form_fields', on_delete=models.CASCADE)


class CustomFormBuilder(FormBuilder):

    def create_multiline_field(self, field, options):
        attrs = {'cols': '20', 'rows': '20'} # default attrs = {'cols': '40', 'rows': '10'}
        return django.forms.CharField(widget=django.forms.Textarea(attrs=attrs), **options)


class FormPage(AbstractEmailForm):

    form_builder = CustomFormBuilder # added - allows us to override the default FormBuilder

    content_panels = AbstractEmailForm.content_panels + [
      #... InlinePanel etc
    ]

更通用的解决方案

  • 在上面的代码的基础上,我们必须选择,使小部件属性可按字段或按页面自定义,所有这些都有其优点和缺点,但让我们每个表单字段都可以自定义自己的属性。
  • 下面我们在 FormField 中添加了一个新的 StreamField,这样我们就可以添加任意 key/value 对,我们可以将其用作 HTML 属性。
  • 由于新的 2.7 StreamField 设计非常小,因此表单页面编辑不会受到太大影响。
  • 然后我们需要在覆盖的 create_multiline_field 方法中读取该字段的数据。
  • 注意:下面的示例仅将属性传递给多行字段,如果您想将属性传递给它们的每个小部件,则需要覆盖每个表单字段方法。
from django.db import models
import django.forms

from modelcluster.fields import ParentalKey

from wagtail.core import blocks
from wagtail.core.fields import StreamField
from wagtail.contrib.forms.forms import FormBuilder
from wagtail.contrib.forms.models import AbstractEmailForm, AbstractFormField
from wagtail.admin.edit_handlers import FieldPanel, FieldRowPanel, InlinePanel, MultiFieldPanel, StreamFieldPanel


class FormField(AbstractFormField):
    attributes = StreamField([
        ('attributes', blocks.StructBlock([
            ('name', blocks.CharBlock()),
            ('value', blocks.CharBlock()),
        ])),
    ], blank=True)

    page = ParentalKey('FormPage', related_name='form_fields', on_delete=models.CASCADE)

    panels = AbstractFormField.panels + [
        StreamFieldPanel('attributes'),
    ]


class CustomFormBuilder(FormBuilder):

    def create_multiline_field(self, field, options):
        # note - to accept attrs - ALL form field methods will need to be updated

        attributes = field.attributes
        attributes_data = attributes.get_prep_value() # convert the streamfield value into a Python data structure
        # outputs [{'value': {'value': '5', 'name': 'rows'}, 'id': '6cb7d669-626c-47c0-bcac-5d982e5d9209', 'type': 'attributes'}]

        keys = [_.get('value').get('name') for _ in attributes_data]
        values = [_.get('value').get('value') for _ in attributes_data]
        attrs = dict(zip(keys, values))
        return django.forms.CharField(widget=django.forms.Textarea(attrs=attrs), **options)


class FormPage(AbstractEmailForm):

    form_builder = CustomFormBuilder # added - allows us to override the default FormBuilder

    content_panels = AbstractEmailForm.content_panels + [
      #... InlinePanel etc
    ]