如何更改 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
- 在此
CustomFormBuilder
class重写方法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
]
我使用 Wagtail 的表单生成器创建了一个表单,其中包含一个多行文本项。当呈现 <textarea>
元素时,它会呈现 rows="10"
。我需要减少行数,但在文档中没有看到任何有关如何执行此操作的信息。
快速解决方案
- 创建一个 class 从
wagtail.contrib.forms.forms
扩展 - 在此
CustomFormBuilder
class重写方法create_multiline_field
- 这个方法应该return一个Django Form Field
- 默认使用的小部件是
Textarea
and the default htmlattrs
列数:40 行数:10 - 在覆盖的方法中,传入您需要的任何自定义属性,例如
attrs = {'cols': '20', 'rows': '20'}
- 最后,确保您的
FormPage
已将form_builder
设置为CustomFormBuilder
class。 - 下面的完整代码片段,这将使所有多行表单字段相同
FormBuilder
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
]