在每个表单字段中添加附加信息 [英] Adding additional information into each form field
问题描述
我正在使用 Django/Wagtail 和 wagtailstreamforms 包来构建表单.不幸的是,您无法在 wagtailstreamforms 表单构建器中并排添加两个字段,因此我尝试添加一个功能,允许用户输入 1 到 12 的整数(基于 Bootstrap 列 - col-1 到col-12) 用于每个字段,此编号将在模板中检索并使用.
在 wagtailstreamforms_fields.py
文件中,我开始覆盖 CharField
模型以添加额外的 width
整数:
from django 导入表单从 wagtailstreamforms.fields 导入 BaseField,注册从 wagtail.core 导入块类 CustomCharField(forms.CharField):def __init__(self,*args, **kwargs):self.width = kwargs.pop('width')super().__init__(*args,**kwargs)@register('单行')Column_SingleLineTextField(BaseField) 类:field_class = CustomCharFielddef get_options(self, block_value):options = super().get_options(block_value)options.update({'width': block_value.get('width')})退货选项def get_formfield(self, block_value):options = super().get_formfield(block_value)退货选项def get_form_block(self):返回 blocks.StructBlock([('label', blocks.CharBlock()),('help_text', blocks.CharBlock(required=False)),('required', blocks.BooleanBlock(required=False)),('default_value', blocks.CharBlock(required=False)),('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),], icon=self.icon, label=self.label)
此代码为 Wagtail 设置中的 wagtailstreamforms 表单构建器页面中的 singleline
字段添加了额外的整数输入.
现在我面临的问题是,我无法在模板中检索 width
参数.
template/custom_form_block.html
文件如下所示:
</表单>
templates/partials/custom_form_field.html
看起来像这样:
{% 加载 form_tags %}<div class="col-{{field.col_width }}">{{ field.label_tag }}{{ 场地 }}{{ field.width }}<p>{% dict 字段 %}</p>{% if field.help_text %}<p class="help-text">{{ field.help_text }}</p>{% endif %}{{ field.errors }}
templatetags/form_tags.py
中的模板标签包含:
from django 导入模板register = template.Library()@register.simple_tagdef dict(this_object):返回 this_object.__dict__
最后,浏览器呈现的页面:
如您所见,dict
模板标签返回表单的所有参数,并且没有传递 width
参数.
如何解决此问题并允许在模板中读取 width
参数?
我粗暴但有效的解决方案
由于我无法覆盖 CharField 模型以添加附加参数 width
,因此我认为利用现有参数来传递 width
会更容易值到模板中.对于这种方法,我将使用 attrs
参数将 width
值传递到每个表单字段的 HTML 呈现实例中,然后我将使用一些 jQuery 来提取值并将其添加到容器div的类中.
从单行 CharField 开始,我们需要覆盖该字段以允许用户输入一个 width
值,我的字段覆盖类如下所示:
@register('单行')Column_SingleLineTextField(BaseField) 类:field_class = CustomSinglelineField图标 = 皮尔克罗"label = "文本字段(单行)";def get_options(self, block_value):options = super().get_options(block_value)options.update({'width': block_value.get('width')})退货选项def get_form_block(self):返回 blocks.StructBlock([('label', blocks.CharBlock()),('help_text', blocks.CharBlock(required=False)),('required', blocks.BooleanBlock(required=False)),('default_value', blocks.CharBlock(required=False)),('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),], icon=self.icon, label=self.label)
现在我们需要重写 CharField 类以将 width
值设置为 attrs
中的属性之一:
class CustomSinglelineField(forms.CharField):def __init__(self,*args,**kwargs):self.width = kwargs.pop('width')self.widget = forms.widgets.TextInput(attrs={'col_width': self.width})super().__init__(*args,**kwargs)
整个代码(wagtailstreamforms_fields.py
)
我还为一些适用的字段添加了一个 placeholder
选项,为多行字段添加了一个 rows
属性选项,以及 width代码>选项:
from django 导入表单从 wagtailstreamforms.fields 导入 BaseField,注册从 wagtail.core 导入块类 CustomSinglelineField(forms.CharField):def __init__(self,*args,**kwargs):self.width = kwargs.pop('width')self.placeholder = kwargs.pop('placeholder')self.widget = forms.widgets.TextInput(attrs={'col_width': self.width, 'placeholder': self.placeholder})super().__init__(*args,**kwargs)类 CustomMultilineField(forms.CharField):def __init__(self,*args,**kwargs):self.width = kwargs.pop('width')self.rows = kwargs.pop('rows')self.placeholder = kwargs.pop('placeholder')self.widget = forms.widgets.Textarea(attrs={'col_width': self.width, 'rows': self.rows, 'placeholder': self.placeholder})super().__init__(*args,**kwargs)类 CustomDateField(forms.DateField):def __init__(self,*args,**kwargs):self.width = kwargs.pop('width')self.widget = forms.widgets.DateInput(attrs={'col_width': self.width})super().__init__(*args,**kwargs)类 CustomDatetimeField(forms.DateField):def __init__(self,*args,**kwargs):self.width = kwargs.pop('width')self.widget = forms.widgets.DateTimeInput(attrs={'col_width': self.width})super().__init__(*args,**kwargs)类 CustomEmailField(forms.EmailField):def __init__(self,*args,**kwargs):self.width = kwargs.pop('width')self.placeholder = kwargs.pop('placeholder')self.widget = forms.widgets.EmailInput(attrs={'col_width': self.width, 'placeholder': self.placeholder})super().__init__(*args,**kwargs)类 CustomURLField(forms.URLField):def __init__(self,*args,**kwargs):self.width = kwargs.pop('width')self.placeholder = kwargs.pop('placeholder')self.widget = forms.widgets.URLInput(attrs={'col_width': self.width, 'placeholder': self.placeholder})super().__init__(*args,**kwargs)类 CustomNumberField(forms.DecimalField):def __init__(self,*args,**kwargs):self.width = kwargs.pop('width')self.placeholder = kwargs.pop('placeholder')self.widget = forms.widgets.URLInput(attrs={'col_width': self.width, 'placeholder': self.placeholder})super().__init__(*args,**kwargs)类 CustomDropdownField(forms.ChoiceField):def __init__(self,*args,**kwargs):self.width = kwargs.pop('width')self.widget = forms.widgets.Select(attrs={'col_width': self.width})super().__init__(*args,**kwargs)类 CustomRadioField(forms.ChoiceField):def __init__(self,*args,**kwargs):self.width = kwargs.pop('width')self.widget = forms.widgets.RadioSelect(attrs={'col_width': self.width})super().__init__(*args,**kwargs)类 CustomCheckboxesField(forms.MultipleChoiceField):def __init__(self,*args,**kwargs):self.width = kwargs.pop('width')self.widget = forms.widgets.SelectMultiple(attrs={'col_width': self.width})super().__init__(*args,**kwargs)类 CustomCheckboxField(forms.BooleanField):def __init__(self,*args,**kwargs):self.width = kwargs.pop('width')self.widget = forms.widgets.CheckboxInput(attrs={'col_width': self.width})super().__init__(*args,**kwargs)类 CustomSinglefileField(forms.FileField):def __init__(self,*args,**kwargs):self.width = kwargs.pop('width')self.widget = forms.widgets.ClearableFileInput(attrs={'col_width': self.width})super().__init__(*args,**kwargs)类 CustomMultifileField(forms.FileField):def __init__(self,*args,**kwargs):self.width = kwargs.pop('width')self.widget = forms.widgets.ClearableFileInput(attrs={'col_width': self.width,multiple": True})super().__init__(*args,**kwargs)@register('单行')Column_SingleLineTextField(BaseField) 类:field_class = CustomSinglelineField图标 = 皮尔克罗"label = "文本字段(单行)";def get_options(self, block_value):options = super().get_options(block_value)options.update({'placeholder': block_value.get('placeholder')})options.update({'width': block_value.get('width')})退货选项def get_form_block(self):返回 blocks.StructBlock([('label', blocks.CharBlock()),('help_text', blocks.CharBlock(required=False)),('required', blocks.BooleanBlock(required=False)),('default_value', blocks.CharBlock(required=False)),('占位符', blocks.CharBlock(required=False)),('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),], icon=self.icon, label=self.label)@register('多行')类 MultiLineTextField(BaseField):field_class = CustomMultilineField图标 = 形式";label = "文本字段(多行)";def get_options(self, block_value):options = super().get_options(block_value)options.update({'width': block_value.get('width')})options.update({'rows': block_value.get('rows')})options.update({'placeholder': block_value.get('placeholder')})退货选项def get_form_block(self):返回 blocks.StructBlock([('label', blocks.CharBlock()),('help_text', blocks.CharBlock(required=False)),('required', blocks.BooleanBlock(required=False)),('default_value', blocks.CharBlock(required=False)),('占位符', blocks.CharBlock(required=False)),('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),('rows', blocks.IntegerBlock(help_text=字段高度", max_value=100, min_value=1, default=10, required=True)),], icon=self.icon, label=self.label)@register('日期')类日期字段(BaseField):field_class = 自定义日期字段图标 = 日期"label = "日期字段";def get_options(self, block_value):options = super().get_options(block_value)options.update({'width': block_value.get('width')})退货选项def get_form_block(self):返回 blocks.StructBlock([('label', blocks.CharBlock()),('help_text', blocks.CharBlock(required=False)),('required', blocks.BooleanBlock(required=False)),('default_value', blocks.CharBlock(required=False)),('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),], icon=self.icon, label=self.label)@register('日期时间')类 DateTimeField(BaseField):field_class = 自定义日期时间字段图标 = 时间"label = "时间字段";def get_options(self, block_value):options = super().get_options(block_value)options.update({'width': block_value.get('width')})退货选项def get_form_block(self):返回 blocks.StructBlock([('label', blocks.CharBlock()),('help_text', blocks.CharBlock(required=False)),('required', blocks.BooleanBlock(required=False)),('default_value', blocks.CharBlock(required=False)),('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),], icon=self.icon, label=self.label)@注册邮件')类 EmailField(BaseField):field_class = CustomEmailField图标 = 邮件"label = "电子邮件字段";def get_options(self, block_value):options = super().get_options(block_value)options.update({'width': block_value.get('width')})options.update({'placeholder': block_value.get('placeholder')})退货选项def get_form_block(self):返回 blocks.StructBlock([('label', blocks.CharBlock()),('help_text', blocks.CharBlock(required=False)),('required', blocks.BooleanBlock(required=False)),('default_value', blocks.CharBlock(required=False)),('占位符', blocks.CharBlock(required=False)),('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),], icon=self.icon, label=self.label)@register('url')类 URLField(BaseField):field_class = CustomURLField图标 = 链接"label = "URL 字段";def get_options(self, block_value):options = super().get_options(block_value)options.update({'width': block_value.get('width')})options.update({'placeholder': block_value.get('placeholder')})退货选项def get_form_block(self):返回 blocks.StructBlock([('label', blocks.CharBlock()),('help_text', blocks.CharBlock(required=False)),('required', blocks.BooleanBlock(required=False)),('default_value', blocks.CharBlock(required=False)),('占位符', blocks.CharBlock(required=False)),('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),], icon=self.icon, label=self.label)@注册号')类 NumberField(BaseField):field_class = forms.DecimalFieldlabel = "数字字段";def get_options(self, block_value):options = super().get_options(block_value)options.update({'width': block_value.get('width')})options.update({'placeholder': block_value.get('placeholder')})退货选项def get_form_block(self):返回 blocks.StructBlock([('label', blocks.CharBlock()),('help_text', blocks.CharBlock(required=False)),('required', blocks.BooleanBlock(required=False)),('default_value', blocks.CharBlock(required=False)),('占位符', blocks.CharBlock(required=False)),('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),], icon=self.icon, label=self.label)@register('下拉菜单')类 DropdownField(BaseField):field_class = CustomDropdownField图标 =向下箭头大";label = "下拉字段";def get_options(self, block_value):options = super().get_options(block_value)options.update({'width': block_value.get('width')})退货选项def get_form_block(self):返回 blocks.StructBlock([(标签", blocks.CharBlock()),(help_text", blocks.CharBlock(required=False)),(必需", blocks.BooleanBlock(required=False)),(empty_label", blocks.CharBlock(required=False)),(选择", blocks.ListBlock(blocks.CharBlock(label=Option"))),('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),],图标=self.icon,标签=self.label,)@register('收音机')类 RadioField(BaseField):field_class = CustomRadioField图标 =无线电空";label = "单选按钮";def get_options(self, block_value):options = super().get_options(block_value)options.update({'width': block_value.get('width')})退货选项def get_form_block(self):返回 blocks.StructBlock([(标签", blocks.CharBlock()),(help_text", blocks.CharBlock(required=False)),(必需", blocks.BooleanBlock(required=False)),(选择", blocks.ListBlock(blocks.CharBlock(label=Option"))),('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),],图标=self.icon,标签=self.label,)@register('复选框')类 CheckboxesField(BaseField):field_class = CustomCheckboxesField图标 = 刻度反转"标签=复选框";def get_options(self, block_value):options = super().get_options(block_value)options.update({'width': block_value.get('width')})退货选项def get_form_block(self):返回 blocks.StructBlock([(标签", blocks.CharBlock()),(help_text", blocks.CharBlock(required=False)),(必需", blocks.BooleanBlock(required=False)),(选择", blocks.ListBlock(blocks.CharBlock(label=Option"))),('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),],图标=self.icon,标签=self.label,)@register('复选框')类 CheckboxField(BaseField):field_class = forms.BooleanField图标 = 刻度反转"label = "复选框字段";def get_options(self, block_value):options = super().get_options(block_value)options.update({'width': block_value.get('width')})退货选项def get_form_block(self):返回 blocks.StructBlock([(标签", blocks.CharBlock()),(help_text", blocks.CharBlock(required=False)),(必需", blocks.BooleanBlock(required=False)),('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),],图标=self.icon,标签=self.label,)@register('单文件')类 SingleFileField(BaseField):field_class = CustomSinglefileFieldicon = "doc-full-inverse";label = "文件字段";def get_options(self, block_value):options = super().get_options(block_value)options.update({'width': block_value.get('width')})退货选项def get_form_block(self):返回 blocks.StructBlock([(标签", blocks.CharBlock()),(help_text", blocks.CharBlock(required=False)),(必需", blocks.BooleanBlock(required=False)),('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),],图标=self.icon,标签=self.label,)@register('多文件')类 MultiFileField(BaseField):field_class = forms.FileFieldicon = "doc-full-inverse";label = "文件字段";def get_form_block(self):返回 blocks.StructBlock([(标签", blocks.CharBlock()),(help_text", blocks.CharBlock(required=False)),(必需", blocks.BooleanBlock(required=False)),('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),],图标=self.icon,标签=self.label,)
现在是模板
templates/custom_form_block.html
没有变化,如下所示:
</表单>
templates/partials/custom_form_field.html
有所有更改,如下所示:
<脚本>var col_width = $(".field-column-id_{{ value.form.slug }}_{{ field.name }} #id_{{ field.name }}").attr("col_width")$(".field-column-id_{{ value.form.slug }}_{{ field.name }}").addClass("col-"+col_width);//设置无"占位符为"var placeholder = $(".field-column-id_{{ value.form.slug }}_{{ field.name }} #id_{{ field.name }}").attr("placeholder")如果(占位符==无"){$(".field-column-id_{{ value.form.slug }}_{{ field.name }} #id_{{ field.name }}").attr("placeholder", "";)}
我将每个字段的父 div 设置为 field-column-id_{{ value.form.slug }}_{{ field.name }}
,这样如果我们有多个表单同一个页面上的同名字段,不会有任何冲突,因为每个表单都会有一个唯一的 slug.
jQuery 检索了我们设置为 width
选项的 col_width
HTML 属性,并将其附加到 col-
并将其设置为父 div 的类.
默认情况下,如果我们没有在 'placeholder' 选项中设置值,wagtailstreamforms 会将此选项设置为 'None'.我们不希望空占位符在 HTML 中显示为无",因此我们有一个 jQuery 脚本,用空字符串替换 None
.这在大多数情况下都有效,但是当用户希望占位符实际设置为 None
时,此功能会中断.
这个解决方案在大多数情况下都有效,但在我看来,我并不为此感到非常自豪,因为我认为这是低效且笨拙的.
I am using Django/Wagtail and the wagtailstreamforms package to build forms. Unfortunately you cannot add two fields side-by-side in the wagtailstreamforms form builder out of the box, so I am trying to add a functionality that allows the user to input an integer 1 to 12 (based on Bootstrap columns - col-1 to col-12) for each field and this number will be retrieved in the templates and will be used.
In the wagtailstreamforms_fields.py
file, I've started to override the CharField
model to add the extra width
integer:
from django import forms
from wagtailstreamforms.fields import BaseField, register
from wagtail.core import blocks
class CustomCharField(forms.CharField):
def __init__(self,*args, **kwargs):
self.width = kwargs.pop('width')
super().__init__(*args,**kwargs)
@register('singleline')
class Column_SingleLineTextField(BaseField):
field_class = CustomCharField
def get_options(self, block_value):
options = super().get_options(block_value)
options.update({'width': block_value.get('width')})
return options
def get_formfield(self, block_value):
options = super().get_formfield(block_value)
return options
def get_form_block(self):
return blocks.StructBlock([
('label', blocks.CharBlock()),
('help_text', blocks.CharBlock(required=False)),
('required', blocks.BooleanBlock(required=False)),
('default_value', blocks.CharBlock(required=False)),
('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),
], icon=self.icon, label=self.label)
This code adds the extra integer input for the singleline
field in the wagtailstreamforms form builder page in Wagtail settings.
Now the issue I'm facing is, I'm not able to retrieve the width
parameter in the templates.
The template/custom_form_block.html
file looks like this:
<form{% if form.is_multipart %} enctype="multipart/form-data"{% endif %} class="row g-3 normal-form" action="{{ value.form_action }}" method="post" novalidate>
{{ form.media }}
{% csrf_token %}
{% for hidden in form.hidden_fields %}{{ hidden }}{% endfor %}
{% for field in form.visible_fields %}
{% include 'partials/custom_form_field.html' %}
{% endfor %}
<div class="col-12">
<button class="btn btn-primary">{{ value.form.submit_button_text }}</button>
</div>
</form>
And the templates/partials/custom_form_field.html
looks like this:
{% load form_tags %}
<div class="col-{{ field.col_width }}">
{{ field.label_tag }}
{{ field }}
{{ field.width }}
<p>{% dict field %}</p>
{% if field.help_text %}<p class="help-text">{{ field.help_text }}</p>{% endif %}
{{ field.errors }}
</div>
And the template tag in templatetags/form_tags.py
contains:
from django import template
register = template.Library()
@register.simple_tag
def dict(this_object):
return this_object.__dict__
And finally, the rendered page from the browser:
As you can see, the dict
template tag returns all the parameters of the form and the width
parameter isn't being passed.
How do I fix this and allow the width
parameter to be read in the templates?
解决方案 My crude but effective solution
As I was unable to override the CharField model to add the additional parameter, width
, I thought it would be easier to utilise an already existing parameter to pass the width
value into the templates. For this approach, I will be using the attrs
parameter to pass the width
value into the HTML rendered instance of each form field, I will then use some jQuery to extract the value and add it to the class of the container div.
Starting with the singleline CharField, we need to override the field to allow the user to input a width
value, my field override class looks like this:
@register('singleline')
class Column_SingleLineTextField(BaseField):
field_class = CustomSinglelineField
icon = "pilcrow"
label = "Text field (single line)"
def get_options(self, block_value):
options = super().get_options(block_value)
options.update({'width': block_value.get('width')})
return options
def get_form_block(self):
return blocks.StructBlock([
('label', blocks.CharBlock()),
('help_text', blocks.CharBlock(required=False)),
('required', blocks.BooleanBlock(required=False)),
('default_value', blocks.CharBlock(required=False)),
('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),
], icon=self.icon, label=self.label)
Now we need to override the CharField class to set the width
value as one of the attributes in attrs
:
class CustomSinglelineField(forms.CharField):
def __init__(self,*args,**kwargs):
self.width = kwargs.pop('width')
self.widget = forms.widgets.TextInput(attrs={'col_width': self.width})
super().__init__(*args,**kwargs)
The whole code (wagtailstreamforms_fields.py
)
I have also added a placeholder
option to some of the applicable fields, a rows
attribute option for the multiline field, as well as the width
option:
from django import forms
from wagtailstreamforms.fields import BaseField, register
from wagtail.core import blocks
class CustomSinglelineField(forms.CharField):
def __init__(self,*args,**kwargs):
self.width = kwargs.pop('width')
self.placeholder = kwargs.pop('placeholder')
self.widget = forms.widgets.TextInput(attrs={'col_width': self.width, 'placeholder': self.placeholder})
super().__init__(*args,**kwargs)
class CustomMultilineField(forms.CharField):
def __init__(self,*args,**kwargs):
self.width = kwargs.pop('width')
self.rows = kwargs.pop('rows')
self.placeholder = kwargs.pop('placeholder')
self.widget = forms.widgets.Textarea(attrs={'col_width': self.width, 'rows': self.rows, 'placeholder': self.placeholder})
super().__init__(*args,**kwargs)
class CustomDateField(forms.DateField):
def __init__(self,*args,**kwargs):
self.width = kwargs.pop('width')
self.widget = forms.widgets.DateInput(attrs={'col_width': self.width})
super().__init__(*args,**kwargs)
class CustomDatetimeField(forms.DateField):
def __init__(self,*args,**kwargs):
self.width = kwargs.pop('width')
self.widget = forms.widgets.DateTimeInput(attrs={'col_width': self.width})
super().__init__(*args,**kwargs)
class CustomEmailField(forms.EmailField):
def __init__(self,*args,**kwargs):
self.width = kwargs.pop('width')
self.placeholder = kwargs.pop('placeholder')
self.widget = forms.widgets.EmailInput(attrs={'col_width': self.width, 'placeholder': self.placeholder})
super().__init__(*args,**kwargs)
class CustomURLField(forms.URLField):
def __init__(self,*args,**kwargs):
self.width = kwargs.pop('width')
self.placeholder = kwargs.pop('placeholder')
self.widget = forms.widgets.URLInput(attrs={'col_width': self.width, 'placeholder': self.placeholder})
super().__init__(*args,**kwargs)
class CustomNumberField(forms.DecimalField):
def __init__(self,*args,**kwargs):
self.width = kwargs.pop('width')
self.placeholder = kwargs.pop('placeholder')
self.widget = forms.widgets.URLInput(attrs={'col_width': self.width, 'placeholder': self.placeholder})
super().__init__(*args,**kwargs)
class CustomDropdownField(forms.ChoiceField):
def __init__(self,*args,**kwargs):
self.width = kwargs.pop('width')
self.widget = forms.widgets.Select(attrs={'col_width': self.width})
super().__init__(*args,**kwargs)
class CustomRadioField(forms.ChoiceField):
def __init__(self,*args,**kwargs):
self.width = kwargs.pop('width')
self.widget = forms.widgets.RadioSelect(attrs={'col_width': self.width})
super().__init__(*args,**kwargs)
class CustomCheckboxesField(forms.MultipleChoiceField):
def __init__(self,*args,**kwargs):
self.width = kwargs.pop('width')
self.widget = forms.widgets.SelectMultiple(attrs={'col_width': self.width})
super().__init__(*args,**kwargs)
class CustomCheckboxField(forms.BooleanField):
def __init__(self,*args,**kwargs):
self.width = kwargs.pop('width')
self.widget = forms.widgets.CheckboxInput(attrs={'col_width': self.width})
super().__init__(*args,**kwargs)
class CustomSinglefileField(forms.FileField):
def __init__(self,*args,**kwargs):
self.width = kwargs.pop('width')
self.widget = forms.widgets.ClearableFileInput(attrs={'col_width': self.width})
super().__init__(*args,**kwargs)
class CustomMultifileField(forms.FileField):
def __init__(self,*args,**kwargs):
self.width = kwargs.pop('width')
self.widget = forms.widgets.ClearableFileInput(attrs={'col_width': self.width,"multiple": True})
super().__init__(*args,**kwargs)
@register('singleline')
class Column_SingleLineTextField(BaseField):
field_class = CustomSinglelineField
icon = "pilcrow"
label = "Text field (single line)"
def get_options(self, block_value):
options = super().get_options(block_value)
options.update({'placeholder': block_value.get('placeholder')})
options.update({'width': block_value.get('width')})
return options
def get_form_block(self):
return blocks.StructBlock([
('label', blocks.CharBlock()),
('help_text', blocks.CharBlock(required=False)),
('required', blocks.BooleanBlock(required=False)),
('default_value', blocks.CharBlock(required=False)),
('placeholder', blocks.CharBlock(required=False)),
('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),
], icon=self.icon, label=self.label)
@register('multiline')
class MultiLineTextField(BaseField):
field_class = CustomMultilineField
icon = "form"
label = "Text field (multiple lines)"
def get_options(self, block_value):
options = super().get_options(block_value)
options.update({'width': block_value.get('width')})
options.update({'rows': block_value.get('rows')})
options.update({'placeholder': block_value.get('placeholder')})
return options
def get_form_block(self):
return blocks.StructBlock([
('label', blocks.CharBlock()),
('help_text', blocks.CharBlock(required=False)),
('required', blocks.BooleanBlock(required=False)),
('default_value', blocks.CharBlock(required=False)),
('placeholder', blocks.CharBlock(required=False)),
('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),
('rows', blocks.IntegerBlock(help_text="Height of field", max_value=100, min_value=1, default=10, required=True)),
], icon=self.icon, label=self.label)
@register('date')
class DateField(BaseField):
field_class = CustomDateField
icon = "date"
label = "Date field"
def get_options(self, block_value):
options = super().get_options(block_value)
options.update({'width': block_value.get('width')})
return options
def get_form_block(self):
return blocks.StructBlock([
('label', blocks.CharBlock()),
('help_text', blocks.CharBlock(required=False)),
('required', blocks.BooleanBlock(required=False)),
('default_value', blocks.CharBlock(required=False)),
('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),
], icon=self.icon, label=self.label)
@register('datetime')
class DateTimeField(BaseField):
field_class = CustomDatetimeField
icon = "time"
label = "Time field"
def get_options(self, block_value):
options = super().get_options(block_value)
options.update({'width': block_value.get('width')})
return options
def get_form_block(self):
return blocks.StructBlock([
('label', blocks.CharBlock()),
('help_text', blocks.CharBlock(required=False)),
('required', blocks.BooleanBlock(required=False)),
('default_value', blocks.CharBlock(required=False)),
('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),
], icon=self.icon, label=self.label)
@register('email')
class EmailField(BaseField):
field_class = CustomEmailField
icon = "mail"
label = "Email field"
def get_options(self, block_value):
options = super().get_options(block_value)
options.update({'width': block_value.get('width')})
options.update({'placeholder': block_value.get('placeholder')})
return options
def get_form_block(self):
return blocks.StructBlock([
('label', blocks.CharBlock()),
('help_text', blocks.CharBlock(required=False)),
('required', blocks.BooleanBlock(required=False)),
('default_value', blocks.CharBlock(required=False)),
('placeholder', blocks.CharBlock(required=False)),
('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),
], icon=self.icon, label=self.label)
@register('url')
class URLField(BaseField):
field_class = CustomURLField
icon = "link"
label = "URL field"
def get_options(self, block_value):
options = super().get_options(block_value)
options.update({'width': block_value.get('width')})
options.update({'placeholder': block_value.get('placeholder')})
return options
def get_form_block(self):
return blocks.StructBlock([
('label', blocks.CharBlock()),
('help_text', blocks.CharBlock(required=False)),
('required', blocks.BooleanBlock(required=False)),
('default_value', blocks.CharBlock(required=False)),
('placeholder', blocks.CharBlock(required=False)),
('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),
], icon=self.icon, label=self.label)
@register('number')
class NumberField(BaseField):
field_class = forms.DecimalField
label = "Number field"
def get_options(self, block_value):
options = super().get_options(block_value)
options.update({'width': block_value.get('width')})
options.update({'placeholder': block_value.get('placeholder')})
return options
def get_form_block(self):
return blocks.StructBlock([
('label', blocks.CharBlock()),
('help_text', blocks.CharBlock(required=False)),
('required', blocks.BooleanBlock(required=False)),
('default_value', blocks.CharBlock(required=False)),
('placeholder', blocks.CharBlock(required=False)),
('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),
], icon=self.icon, label=self.label)
@register('dropdown')
class DropdownField(BaseField):
field_class = CustomDropdownField
icon = "arrow-down-big"
label = "Dropdown field"
def get_options(self, block_value):
options = super().get_options(block_value)
options.update({'width': block_value.get('width')})
return options
def get_form_block(self):
return blocks.StructBlock(
[
("label", blocks.CharBlock()),
("help_text", blocks.CharBlock(required=False)),
("required", blocks.BooleanBlock(required=False)),
("empty_label", blocks.CharBlock(required=False)),
("choices", blocks.ListBlock(blocks.CharBlock(label="Option"))),
('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),
],
icon=self.icon,
label=self.label,
)
@register('radio')
class RadioField(BaseField):
field_class = CustomRadioField
icon = "radio-empty"
label = "Radio buttons"
def get_options(self, block_value):
options = super().get_options(block_value)
options.update({'width': block_value.get('width')})
return options
def get_form_block(self):
return blocks.StructBlock(
[
("label", blocks.CharBlock()),
("help_text", blocks.CharBlock(required=False)),
("required", blocks.BooleanBlock(required=False)),
("choices", blocks.ListBlock(blocks.CharBlock(label="Option"))),
('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),
],
icon=self.icon,
label=self.label,
)
@register('checkboxes')
class CheckboxesField(BaseField):
field_class = CustomCheckboxesField
icon = "tick-inverse"
label = "Checkboxes"
def get_options(self, block_value):
options = super().get_options(block_value)
options.update({'width': block_value.get('width')})
return options
def get_form_block(self):
return blocks.StructBlock(
[
("label", blocks.CharBlock()),
("help_text", blocks.CharBlock(required=False)),
("required", blocks.BooleanBlock(required=False)),
("choices", blocks.ListBlock(blocks.CharBlock(label="Option"))),
('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),
],
icon=self.icon,
label=self.label,
)
@register('checkbox')
class CheckboxField(BaseField):
field_class = forms.BooleanField
icon = "tick-inverse"
label = "Checkbox field"
def get_options(self, block_value):
options = super().get_options(block_value)
options.update({'width': block_value.get('width')})
return options
def get_form_block(self):
return blocks.StructBlock(
[
("label", blocks.CharBlock()),
("help_text", blocks.CharBlock(required=False)),
("required", blocks.BooleanBlock(required=False)),
('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),
],
icon=self.icon,
label=self.label,
)
@register('singlefile')
class SingleFileField(BaseField):
field_class = CustomSinglefileField
icon = "doc-full-inverse"
label = "File field"
def get_options(self, block_value):
options = super().get_options(block_value)
options.update({'width': block_value.get('width')})
return options
def get_form_block(self):
return blocks.StructBlock(
[
("label", blocks.CharBlock()),
("help_text", blocks.CharBlock(required=False)),
("required", blocks.BooleanBlock(required=False)),
('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),
],
icon=self.icon,
label=self.label,
)
@register('multifile')
class MultiFileField(BaseField):
field_class = forms.FileField
icon = "doc-full-inverse"
label = "Files field"
def get_form_block(self):
return blocks.StructBlock(
[
("label", blocks.CharBlock()),
("help_text", blocks.CharBlock(required=False)),
("required", blocks.BooleanBlock(required=False)),
('width', blocks.IntegerBlock(help_text="Width of field, 1 to 12, 12 is full width.", max_value=12, min_value=1, default=12, required=True)),
],
icon=self.icon,
label=self.label,
)
Now the templates
The templates/custom_form_block.html
is unchanged and looks like the following:
<form{% if form.is_multipart %} enctype="multipart/form-data"{% endif %} class="row g-3 normal-form" action="{{ value.form_action }}" method="post" novalidate>
{{ form.media }}
{% csrf_token %}
{% for hidden in form.hidden_fields %}{{ hidden }}{% endfor %}
{% for field in form.visible_fields %}
{% include 'partials/custom_form_field.html' %}
{% endfor %}
<div class="col-12">
<button class="btn btn-primary">{{ value.form.submit_button_text }}</button>
</div>
</form>
And the templates/partials/custom_form_field.html
has all the changes and looks like the following:
<div class="field-column-id_{{ value.form.slug }}_{{ field.name }}">
{{ field.label_tag }}
{{ field }}
{% if field.help_text %}<p class="help-text">{{ field.help_text }}</p>{% endif %}
{{ field.errors }}
</div>
<script>
var col_width = $(".field-column-id_{{ value.form.slug }}_{{ field.name }} #id_{{ field.name }}").attr("col_width")
$(".field-column-id_{{ value.form.slug }}_{{ field.name }}").addClass("col-"+col_width);
// Set the "None" placeholders as ""
var placeholder = $(".field-column-id_{{ value.form.slug }}_{{ field.name }} #id_{{ field.name }}").attr("placeholder")
if (placeholder == "None") {
$(".field-column-id_{{ value.form.slug }}_{{ field.name }} #id_{{ field.name }}").attr("placeholder", "")
}
</script>
I am setting the parent div for each field as field-column-id_{{ value.form.slug }}_{{ field.name }}
, this way if we have multiple forms with fields of the same name on the same page, there wouldn't be any conflicts as each form will have a unique slug.
The jQuery retrieved the col_width
HTML attribute that we set as the width
option and will append it to col-
and set it as the parent div's class.
By default, if we don't set a value in the 'placeholder' option, wagtailstreamforms sets this option as 'None'. We don't want an empty placeholder to be displayed as 'None' in the HTML so we have a jQuery script that replaces None
with an empty string. This will work for the most part but this functionality breaks when the user wants the placeholder to actually be set to None
.
This solution works for the most part, but in my honest opinion, I'm not very proud of it as I think this is inefficient and hacky.
这篇关于在每个表单字段中添加附加信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文