Roman Nozhenko
Roman Nozhenko

Reputation: 628

Wagtail Feedback form in homepage

Tell me how to get the Wagtail form not in its separate template but on the homepage, since I do not need lending and another page. I can not find how to specify it in the get_context of the Home model

Upvotes: 0

Views: 638

Answers (1)

LB Ben Johnston
LB Ben Johnston

Reputation: 5196

This is very similar to the question/answer about putting a form on every page.

Nonetheless, here is a way to implement this solution.

Example

In your my_app/models.py -

class HomePage(Page):
    """A Page model that represents the home page at the root of all pages."""

    # must have way to know WHICH FormPage to use, this makes it user editable
    form_page = models.ForeignKey(
        'wagtailcore.Page',
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
        related_name='embedded_form_page',
        help_text='Select a Form that will be embedded on this page.')

    # ... all other fields

    def get_context(self, request, *args, **kwargs):
        """Add a renderable form to the page's context if form_page is set."""
        # context = super(HomePage, self).get_context(request, *args, **kwargs) # python 2.7 syntax
        context = super().get_context(request, *args, **kwargs)
        if self.form_page:
            form_page = self.form_page.specific  # must get the specific page
            # form will be a renderable form as per the dedicated form pages
            form = form_page.get_form(page=form_page, user=request.user)
            context['form'] = form
        return context

    content_panels = Page.content_panels + [
        PageChooserPanel('form_page', ['base.FormPage']), # Important: ensure only a FormPage model can be selected
        #... other fields
    ]

Then in your template my_app/templates/my_app/home_page.html

<div>
  {% if self.form_page %}
    <form action="{% pageurl self.form_page %}" method="POST" role="form">
      {% csrf_token %}
      {{ form.as_p }} {# form is avaialable in the context #}
      <input type="submit">
    </form>
  {% endif %}
</div>

Explanation

  • First we provide a way to know which FormPage we want to render, we could assume by just grabbing the first one with FormPage.objects.get() but this is bad practice and could be unreliable. This is why we have added a ForeignKey to wagtailcore.Page - note we do not link to our FormPage model here.
  • Then we restrict the linking inside the PageChooserPanel, in the example our FormPage model is located in the base app, hence ['base.FormPage].
  • Then we override the get_context method, the only real reason we need to do this as it gets us the current request and FormPage.getForm needs the current request to be used.
  • Finally, we update our template following the form rendering example in the docs pretty closely. With the difference being that our POST URL for the form is actually the form_page not the current page (homePage).
  • Important Note: The form actually POSTS to the form page, not your home page, this means that we do not need to handle any kind of POST request to the home_page. It is a simple solution but it means that the landing page will be rendered ad the form page's URL.

Upvotes: 2

Related Questions