Sam Houston
Sam Houston

Reputation: 3661

Wagtail not pulling through custom field panels

I'm overriding the wagtail AbstractFormField panel attribute in the following way:

...
before_input = RichTextField(verbose_name=_('before input'), blank=True)
after_input = RichTextField(verbose_name=_('after input'), blank=True)

panels = [
    FieldPanel('label'),
    FieldPanel('before_input'),
    FieldPanel('after_input'),
    FieldPanel('required'),
    FieldPanel('field_type', classname="formbuilder-type"),
    FieldPanel('choices', classname="formbuilder-choices"),
    FieldPanel('default_value', classname="formbuilder-default"),
]

where the other panels are what comes out of the box.


This is working perfectly on the admin side and also saving as rich text into my database


I am pulling this through to my form in my template in the following way:

<form action="{% pageurl page %}" method="POST" class="lm-ls1" id="feedback-form">
  {% csrf_token %}

  {{ form.question1.help_text }} <!-- Simpler non interable way -->
  {{ form.question1.before_input }}

  <p>---------------</p>
  {% for row in form.fields.values %}
    {{row.choices}}
    <p>---------------</p>
    {{row.help_text}}
    <p>---------------</p>
    {{row.before_input}}
  {% endfor %}
</form>

But I am only getting html output for the form panels excluding the before_input and after_input ones

I am getting through roughly the following:

Overall, how did you feel about the service you received today?
---------------

[('Very satisfied', 'Very satisfied'), ('Satisfied', 'Satisfied'),
 ('Neither satisfied nor dissatisfied', 'Neither satisfied nor dissatisfied'), ('Dissatisfied', 'Dissatisfied'), ('Very dissatisfied', 'Very dissatisfied')]
---------------

Overall, how did you feel about the service you received today?
---------------

---------------

How can I access the before_input field panel data stored in the _formfield wagtail table?

Upvotes: 1

Views: 1035

Answers (1)

LB Ben Johnston
LB Ben Johnston

Reputation: 5196

Bit late but hopefully this still helps you or someone else out there.

How Wagtail Forms Work

Wagtail forms provided to the view context for AbstractFormPage models is a fully instanced Django Form. This means that you will only ever find values in the form that can be given to a Django Form.

This includes fields, which are instances of Django's Fields (eg. CharField) and there is no simple way to add additional attributes to these fields.

You can see how the Form object is built in the Wagtail FormBuilder class definition.

1 - Make a Custom Template Tag

A somewhat simple way to get additional attributes on your FormField (Wagtail's FormField) is using a template tag.

Create a new file in in a folder templatetags in your app, and build a simple_tag that will take the form_page, the field (which will be a Django Field instance) and a string of the attribute name you want to get.

# myapp/templatetags/form_tags.py
from django import template
from django.utils.html import mark_safe

register = template.Library()


@register.simple_tag(name='form_field_attribute')
def form_field_attribute(form_page, field, attribute_name, default=None):
    """Return attribute on FormField where field matches 'field' provided."""
    # field is a django Field instance
    field_name = field.name
    results = [
        # if html is stored, need to use mark_safe - be careful though.
        mark_safe(getattr(form_field, attribute_name, default))
        # get_form_fields() is a built in function on AbstractFormPage
        for form_field in form_page.get_form_fields()
        # clean_name is property on AbstractFormField used for Django Field name
        if form_field.clean_name == field_name]
    if results:
        return results[0]
    return default

2 - Revise your form_page.html Template

In your template, cycle through your form (this is the Django Form instance) and use the template helper to get you the extra attributes you need. Example below, passing in page or self will work the same as they are both the instance of your FormPage.

<form action="{% pageurl page %}" method="POST" role="form">
    {% csrf_token %}
    {% for field in form %}
      <div>{% form_field_attribute page field 'before_input' %}</div>
      {{ field }}
      <div>{% form_field_attribute page field 'after_input' %}</div>
    {% endfor %}
    <input type="submit">
</form>

Upvotes: 1

Related Questions