[Django]-How can I add a form made by formbuilder to every page in Wagtail?

7👍

The main issue is how you are generating the form in the template with .form.as_p.

You will need to generate the form with the .get_form function, but you are best to do it within your template as the current user and page needs to be past in as arguments like this.

        form = feedback_form_page.get_form(
        page=feedback_form_page, user=request.user)

You can see how the form is built for the AbstractForm model here:
https://github.com/wagtail/wagtail/blob/master/wagtail/wagtailforms/models.py#L278

Full detailed example below, along with how you could work the form selection into the Site Settings module.

Link to a Form in Site Settings

Assuming you are referring to the Site Settings contrib module:
http://docs.wagtail.io/en/v1.13/reference/contrib/settings.html

The ‘Edit Handlers’ section of the documentation explains a great way to link to a page inside of your site settings.
http://docs.wagtail.io/en/v1.13/reference/contrib/settings.html?highlight=site%20settings#edit-handlers

Example (in models.py):

from wagtail.contrib.settings.models import BaseSetting, register_setting
# ...
@register_setting
class MyCustomSettings(BaseSetting):
    feedback_form_page = models.ForeignKey(
        'wagtailcore.Page', null=True, on_delete=models.SET_NULL)

    panels = [
        # note the page type declared within the pagechooserpanel
        PageChooserPanel('feedback_form_page', ['base.FormPage']),
    ]

Once you set this model up, you will need to do makemigration and migrate for the changes to work in admin. You will then see inside the settings menu a sub-menu titled ‘My Custom Settings’

Adding linked Form to every page

Add a block (so it can be overridden in templates) that has an include in your base template (eg. myapp/templates/base.html).

<!-- Footer -->
<footer>
    {% block feedback_form %}{% include "includes/feedback_form.html" %}{% endblock feedback_form %}
    {% include "includes/footer.html" %}
</footer>

Create an include template (eg. myapp/templates/includes/feedback_form.html)

{% load feedback_form_tags wagtailcore_tags %}

{% get_feedback_form as feedback_form %}

<form action="{% pageurl feedback_form.page %}" method="POST" role="form">
  <h3>{{ feedback_form.page.title}}</h3>
  {% csrf_token %}
  {{ feedback_form.form.as_p }}
  <input type="submit">
</form>

Build a Template Tag to get the form and page

Your template tag needs to build the form with the page’s self.get_form() function. Eg. you your template tag (base/templatetags/feedback_form)

from django import template
from myapp.models import MyCustomSettings

register = template.Library()
# https://docs.djangoproject.com/en/1.9/howto/custom-template-tags/


@register.assignment_tag(takes_context=True)
def get_feedback_form(context):
    request = context['request']
    my_custom_settings = MyCustomSettings.for_site(request.site)
    feedback_form_page = my_custom_settings.feedback_form_page.specific
    form = feedback_form_page.get_form(
        page=feedback_form_page, user=request.user)
    return {'page': feedback_form_page, 'form': form}

2👍

This still works in wagtail 2.3 just need to replace

@register.assignment_tag(takes_context=True)

with

@register.simple_tag(takes_context=True) to conform with django 2.2

Also {% load feedback_form_tags wagtailcore_tags %} assumes your file inside of templates tags is named feedback_form_tags.py. I also added an __init__.py in the template tags folder although I’m not sure that was actually necessary.

Leave a comment