【问题标题】:How to modify attributes of the Wagtail form input fields?如何修改 Wagtail 表单输入字段的属性?
【发布时间】:2018-01-18 12:48:36
【问题描述】:

我在看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">

如何修改/添加额外属性到呈现的输入字段?

例如:

  • 如何添加class="form-control"
  • 如何在textarea 输入中更改rows="5"

除了疯狂的javascript还有其他方便的方法吗?

【问题讨论】:

    标签: django django-forms wagtail


    【解决方案1】:

    我假设您想要更改 FormPage 的呈现方式(即扩展 AbstractEmailFormAbstractForm 的页面)。

    有一些方法可以在您的 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),默认情况下 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所有 textarea 输入,并将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 可以为您省去很多麻烦。

    【讨论】:

    • 太棒了! 2 年后,这有助于提升我对同事的自尊心。谢谢你。我对此进行了修改以向每个表单字段添加占位符文本。我在我的案例中使用帮助文本,因为我们不在这个特定项目中使用它。 field.widget.attrs.update({'placeholder': field.help_text})
    • 太棒了。
    【解决方案2】:

    您可以创建动态模板:
    通过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 %}
    

    【讨论】:

      【解决方案3】:

      您可以将widget 参数传递给FieldPanel,以定义与该字段一起使用的Django widget object。除此之外,这还允许您自定义显示在字段上的 HTML 属性:

      from django import forms
      
      class FormPage(AbstractEmailForm):
          content_panels = [
              # ...
              FieldPanel('subject', widget=forms.TextInput(attrs={'class': 'form-control'})),
          ]
      

      【讨论】:

        【解决方案4】:

        这是 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' 的东西,也许可以创建一个更优雅的解决方案.

        此来源现在以Wagtail app on GitHub. 的形式提供

        【讨论】:

          猜你喜欢
          • 2015-01-20
          • 2013-07-18
          • 1970-01-01
          • 2022-11-02
          • 1970-01-01
          • 2014-04-04
          • 1970-01-01
          • 2012-07-11
          • 1970-01-01
          相关资源
          最近更新 更多