在每个表单字段中添加附加信息 [英] Adding additional information into each form field

查看:46
本文介绍了在每个表单字段中添加附加信息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 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 文件如下所示:

{{ form.media }}{% csrf_token %}{% for hidden in form.hidden_​​fields %}{{ hidden }}{% endfor %}{% for field in form.visible_fields %}{% 包含 'partials/custom_form_field.html' %}{% 结束为 %}<div class="col-12"><button class="btn btn-primary">{{ value.form.submit_button_text }}</button>

</表单>

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 没有变化,如下所示:

{{ form.media }}{% csrf_token %}{% for hidden in form.hidden_​​fields %}{{ hidden }}{% endfor %}{% for field in form.visible_fields %}{% 包含 'partials/custom_form_field.html' %}{% 结束为 %}<div class="col-12"><button class="btn btn-primary">{{ value.form.submit_button_text }}</button>

</表单>

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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆