如何修改 Wagtail 表单输入字段的属性?
How to modify attributes of the Wagtail form input fields?
我正在查看 wagtail
hello-world form
示例:
class FormField(AbstractFormField):
page = ParentalKey('FormPage', related_name='form_fields')
class FormPage(AbstractEmailForm):
landing_page_template = 'blog/form_page.html'
intro = RichTextField(blank=True)
thank_you_text = RichTextField(blank=True)
content_panels = AbstractEmailForm.content_panels + [
FormSubmissionsPanel(),
FieldPanel('intro', classname="full"),
InlinePanel('form_fields', label="Form fields"),
FieldPanel('thank_you_text', classname="full"),
MultiFieldPanel([
FieldRowPanel([
FieldPanel('from_address', classname="col6"),
FieldPanel('to_address', classname="col6"),
]),
FieldPanel('subject'),
], "Email"),
]
如果给出这样的模板:
{% for field in form %}
{{ field }}
{% endfor %}
它将呈现 HTML 类似于以下内容:
<input type="text" name="label1" value="Default Label1" required maxlength="255" id="id_label1" />
<input type="url" name="label2" value="http://Label2.net" id="id_label2" />
<textarea name="label3" required rows="10" id="id_label3" cols="40">
如何 modify/add 渲染输入字段的额外属性?
例如:
- 如何添加
class="form-control"
?
- 如何更改
textarea
输入中的 rows="5"
?
除了javascript疯狂,还有其他方便的方法吗?
您可以将 widget
参数传递给 FieldPanel
,以定义要与该字段一起使用的 Django widget object。除其他外,这允许您自定义出现在字段上的 HTML 属性:
from django import forms
class FormPage(AbstractEmailForm):
content_panels = [
# ...
FieldPanel('subject', widget=forms.TextInput(attrs={'class': 'form-control'})),
]
我假设您想要更改 FormPage
的呈现方式(即扩展 AbstractEmailForm
或 AbstractForm
的页面)。
有一些方法可以在您的 form_page.html
模板中执行此操作(请参阅答案底部的链接),但是,我认为最好的办法是在这些属性到达模板之前添加这些属性。
这样您就可以让您的模板非常简单,甚至只需使用 docs example.
中的复制和粘贴即可
{% load wagtailcore_tags %}
<html>
<head>
<title>{{ page.title }}</title>
</head>
<body>
<h1>{{ page.title }}</h1>
{{ page.intro|richtext }}
<form action="{% pageurl page %}" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit">
</form>
</body>
</html>
然后,在 my_app/models.py
中,您想覆盖 FormPage
上的 get_form
方法。您可以在 Wagtail form/models.py code.
中查看 get_form
方法的作用
您需要确保通过 super 获取生成的 form
对象。然后遍历字段 - 更新每个字段上的小部件。小部件用于呈现输入字段(或文本区域),默认情况下 Textarea widget 包含 10 行和 40 列。
您还可以使用 class
键更新任何小部件上的 attrs
字典,以将自定义 类 添加到呈现的输入中。这样我们就可以将 form-control
添加到每个输入。
参见示例:
from django.forms import widgets # used to find TextArea widget
# other imports.... AbstractEmailForm etc
class FormPage(AbstractEmailForm):
# body, thank_you_text, etc
def get_form(self, *args, **kwargs):
form = super().get_form(*args, **kwargs)
# form = super(AbstractEmailForm, self).get_form(*args, **kwargs) # use this syntax for Python 2.x
# iterate through the fields in the generated form
for name, field in form.fields.items():
# here we want to adjust the widgets on each field
# if the field is a TextArea - adjust the rows
if isinstance(field.widget, widgets.Textarea):
field.widget.attrs.update({'rows': '5'})
# for all fields, get any existing CSS classes and add 'form-control'
# ensure the 'class' attribute is a string of classes with spaces
css_classes = field.widget.attrs.get('class', '').split()
css_classes.append('form-control')
field.widget.attrs.update({'class': ' '.join(css_classes)})
return form
这将在 html 属性中呈现 所有 文本区域输入 rows=5
,并将 form-control
添加到 class
所有输入的属性(如果使用,甚至是隐藏的输入)。请记住,这将改变每个正在使用的 FormPage
。
对于在模板中更复杂的表单呈现,这篇文章非常好,但内容非常全面:https://simpleisbetterthancomplex.com/article/2017/08/19/how-to-render-django-form-manually.html#accessing-the-form-fields-individually
此外,对于基本的 Bootstrap 3(或 4)个表单呈现,Crispy Forms 可以为您省去很多麻烦。
您可以创建动态模板:
通过 form
创建循环
django doc
{% for field in form.visible_fields %}
<div>
<div class="form-group mb-10">
{{ field.errors }}
{{ field.label_tag }}
<input type="{{ field.field.widget.input_type }}" class="form-control"
name="{{ field.name }}" id="{{ field.id_for_label }}"
{% if field.field.required %}required="required"{% endif %}>
{% comment %}you might want form field for textarea or select etc. just make conditions for those {% endcomment %}
</div>
</div>
{% endfor %}
这是 w411-3 提供的答案的扩展 ...
如果您想将所有这些都保留在模板中,并拥有多行 textarea,您可以利用 {{ field.field.widget.input_type }} 它为除 textarea 字段之外的所有字段提供 True。
<form action="{% pageurl page %}" method="POST">
{% csrf_token %}
{% for field in form.visible_fields %}
<div class="form-group mb-10">
{{ field.errors }}
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{% if field.field.widget.input_type %}
<input type="{% if field.field.widget.input_type == 'number' %}
tel
{% else %}
{{ field.field.widget.input_type }}
{% endif %}"
class="form-control"
name="{{ field.name }}"
id="{{ field.id_for_label }}"
placeholder="{{ field.help_text }}"
{% if field.field.required %}required="required"{% endif %}>
{% else %}
<textarea type="{{ field.field.widget.input_type }}"
class="form-control"
name="{{ field.name }}"
id="{{ field.id_for_label }}"
placeholder="{{ field.help_text }}"
{% if field.field.required %}required="required"{% endif %}
></textarea>
{% endif %}
</div>
{% endfor %}
<input type="submit">
</form>
您可以将 html label 定义替换为:{{ field.label_tag }},但是此方法允许您轻松添加额外的 css 类 如果需要的话。
输入类型中的if语句删除了自动添加到数字字段的箭头/微调器。出于某种原因,Wagtail 不提供表单中的电话数据类型,因此没有必要这样做。
注意:如果您想为每种表单类型自定义元素,请查看 Rendering Templates for StreamFields 上的 Wagtail 文档。而不是 if block.block_type == 'heading' 你可以使用类似于 field.field.widget.input_type == 'number'[= 的东西34=],也许可以创建一个更优雅的解决方案。
此来源现在可作为 Wagtail app on GitHub.
我正在查看 wagtail
hello-world form
示例:
class FormField(AbstractFormField):
page = ParentalKey('FormPage', related_name='form_fields')
class FormPage(AbstractEmailForm):
landing_page_template = 'blog/form_page.html'
intro = RichTextField(blank=True)
thank_you_text = RichTextField(blank=True)
content_panels = AbstractEmailForm.content_panels + [
FormSubmissionsPanel(),
FieldPanel('intro', classname="full"),
InlinePanel('form_fields', label="Form fields"),
FieldPanel('thank_you_text', classname="full"),
MultiFieldPanel([
FieldRowPanel([
FieldPanel('from_address', classname="col6"),
FieldPanel('to_address', classname="col6"),
]),
FieldPanel('subject'),
], "Email"),
]
如果给出这样的模板:
{% for field in form %}
{{ field }}
{% endfor %}
它将呈现 HTML 类似于以下内容:
<input type="text" name="label1" value="Default Label1" required maxlength="255" id="id_label1" />
<input type="url" name="label2" value="http://Label2.net" id="id_label2" />
<textarea name="label3" required rows="10" id="id_label3" cols="40">
如何 modify/add 渲染输入字段的额外属性?
例如:
- 如何添加
class="form-control"
? - 如何更改
textarea
输入中的rows="5"
?
除了javascript疯狂,还有其他方便的方法吗?
您可以将 widget
参数传递给 FieldPanel
,以定义要与该字段一起使用的 Django widget object。除其他外,这允许您自定义出现在字段上的 HTML 属性:
from django import forms
class FormPage(AbstractEmailForm):
content_panels = [
# ...
FieldPanel('subject', widget=forms.TextInput(attrs={'class': 'form-control'})),
]
我假设您想要更改 FormPage
的呈现方式(即扩展 AbstractEmailForm
或 AbstractForm
的页面)。
有一些方法可以在您的 form_page.html
模板中执行此操作(请参阅答案底部的链接),但是,我认为最好的办法是在这些属性到达模板之前添加这些属性。
这样您就可以让您的模板非常简单,甚至只需使用 docs example.
中的复制和粘贴即可{% load wagtailcore_tags %}
<html>
<head>
<title>{{ page.title }}</title>
</head>
<body>
<h1>{{ page.title }}</h1>
{{ page.intro|richtext }}
<form action="{% pageurl page %}" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit">
</form>
</body>
</html>
然后,在 my_app/models.py
中,您想覆盖 FormPage
上的 get_form
方法。您可以在 Wagtail form/models.py code.
get_form
方法的作用
您需要确保通过 super 获取生成的 form
对象。然后遍历字段 - 更新每个字段上的小部件。小部件用于呈现输入字段(或文本区域),默认情况下 Textarea widget 包含 10 行和 40 列。
您还可以使用 class
键更新任何小部件上的 attrs
字典,以将自定义 类 添加到呈现的输入中。这样我们就可以将 form-control
添加到每个输入。
参见示例:
from django.forms import widgets # used to find TextArea widget
# other imports.... AbstractEmailForm etc
class FormPage(AbstractEmailForm):
# body, thank_you_text, etc
def get_form(self, *args, **kwargs):
form = super().get_form(*args, **kwargs)
# form = super(AbstractEmailForm, self).get_form(*args, **kwargs) # use this syntax for Python 2.x
# iterate through the fields in the generated form
for name, field in form.fields.items():
# here we want to adjust the widgets on each field
# if the field is a TextArea - adjust the rows
if isinstance(field.widget, widgets.Textarea):
field.widget.attrs.update({'rows': '5'})
# for all fields, get any existing CSS classes and add 'form-control'
# ensure the 'class' attribute is a string of classes with spaces
css_classes = field.widget.attrs.get('class', '').split()
css_classes.append('form-control')
field.widget.attrs.update({'class': ' '.join(css_classes)})
return form
这将在 html 属性中呈现 所有 文本区域输入 rows=5
,并将 form-control
添加到 class
所有输入的属性(如果使用,甚至是隐藏的输入)。请记住,这将改变每个正在使用的 FormPage
。
对于在模板中更复杂的表单呈现,这篇文章非常好,但内容非常全面:https://simpleisbetterthancomplex.com/article/2017/08/19/how-to-render-django-form-manually.html#accessing-the-form-fields-individually
此外,对于基本的 Bootstrap 3(或 4)个表单呈现,Crispy Forms 可以为您省去很多麻烦。
您可以创建动态模板:
通过 form
创建循环
django doc
{% for field in form.visible_fields %}
<div>
<div class="form-group mb-10">
{{ field.errors }}
{{ field.label_tag }}
<input type="{{ field.field.widget.input_type }}" class="form-control"
name="{{ field.name }}" id="{{ field.id_for_label }}"
{% if field.field.required %}required="required"{% endif %}>
{% comment %}you might want form field for textarea or select etc. just make conditions for those {% endcomment %}
</div>
</div>
{% endfor %}
这是 w411-3 提供的答案的扩展 ...
如果您想将所有这些都保留在模板中,并拥有多行 textarea,您可以利用 {{ field.field.widget.input_type }} 它为除 textarea 字段之外的所有字段提供 True。
<form action="{% pageurl page %}" method="POST">
{% csrf_token %}
{% for field in form.visible_fields %}
<div class="form-group mb-10">
{{ field.errors }}
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{% if field.field.widget.input_type %}
<input type="{% if field.field.widget.input_type == 'number' %}
tel
{% else %}
{{ field.field.widget.input_type }}
{% endif %}"
class="form-control"
name="{{ field.name }}"
id="{{ field.id_for_label }}"
placeholder="{{ field.help_text }}"
{% if field.field.required %}required="required"{% endif %}>
{% else %}
<textarea type="{{ field.field.widget.input_type }}"
class="form-control"
name="{{ field.name }}"
id="{{ field.id_for_label }}"
placeholder="{{ field.help_text }}"
{% if field.field.required %}required="required"{% endif %}
></textarea>
{% endif %}
</div>
{% endfor %}
<input type="submit">
</form>
您可以将 html label 定义替换为:{{ field.label_tag }},但是此方法允许您轻松添加额外的 css 类 如果需要的话。
输入类型中的if语句删除了自动添加到数字字段的箭头/微调器。出于某种原因,Wagtail 不提供表单中的电话数据类型,因此没有必要这样做。
注意:如果您想为每种表单类型自定义元素,请查看 Rendering Templates for StreamFields 上的 Wagtail 文档。而不是 if block.block_type == 'heading' 你可以使用类似于 field.field.widget.input_type == 'number'[= 的东西34=],也许可以创建一个更优雅的解决方案。
此来源现在可作为 Wagtail app on GitHub.