Reputation: 309
The Wagtail Form Builder documentation states:
form_page.html differs from a standard Wagtail template in that it is passed a variable
form
, containing a Django Form object, in addition to the usualpage
variable.
But in my current project, I need to embed a contact form (implemented as a Form Builder page) in another page. In the model for that target page, I'm using a PageChooserPanel to let an editor select the form page to embed. In other words:
class TargetPage(Page):
[...snip...]
contact_form = models.ForeignKey(
'wagtailcore.Page',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+',
)
content_panels = Page.content_panels + [
[...snip...]
PageChooserPanel('contact_form', 'FormPage'),
]
My problem is in the template for the target page. I can access the attributes of the form page via page.contact_form
, but since this page doesn't have a form
object passed in, I can't figure out how to render my fields.
I am guessing that I need to override my target page's get_context() so that it includes the form
object I need. But I can't figure out how to get that object. Can some kind soul put me on the right track?
Upvotes: 4
Views: 666
Reputation: 691
#home/models.py
class HomePage(Page):
subscription_form = models.ForeignKey(
'wagtailcore.Page',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+',
)
content_panels = Page.content_panels + [
PageChooserPanel('subscription_form', 'home.FormPage'),
]
def attached_form(self):
return self.subscription_form.specific.get_form()
def attached_form_url(self):
return self.subscription_form.get_url();
.... #home/models.py
class FormField(AbstractFormField):
page = ParentalKey(
"FormPage", related_name="form_fields", on_delete=models.CASCADE)
... #home/models.py
class FormPage(AbstractEmailForm):
image = models.ForeignKey(
"wagtailimages.Image",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="+",
)
body = StreamField(BaseStreamBlock(), use_json_field=True)
thank_you_text = RichTextField(blank=True)
# Note how we include the FormField object via an InlinePanel using the
# related_name value
content_panels = AbstractEmailForm.content_panels + [
FieldPanel("image"),
FieldPanel("body"),
InlinePanel("form_fields", heading="Form fields", label="Field"),
FieldPanel("thank_you_text"),
MultiFieldPanel(
[
FieldRowPanel(
[
FieldPanel("from_address"),
FieldPanel("to_address"),
]
),
FieldPanel("subject"),
],
"Email",
),
]
In "home/templates/home/home_page.html
I am using tailwind css.
<style>
input, textarea {
width: 100%;
background: rgb(209 213 219 / var(--tw-bg-opacity));
border-radius: 6px;
padding: 0.75rem;
}
</style>
<form class="pt-16 form" action="{{ page.attached_form_url }}" method="POST">
{% csrf_token %}
{% for field in page.attached_form %}
<div class="pt-10 grid grid-cols-1 md:grid-cols-5 px-4">
<div> </div>
<div class="col-span-3 w-full">
<div class="container flex flex-col xl:flex-row mx-auto px-5 py-8 xl:py-14 text-gray-500 bg-gray-200 rounded-2xl">
<div class="w-full mb-6 xl:mb-0 sm:text-center">
<div class="mb-4 text-gray-900 text-3xl font-extrabold">Join 2,000+ subscribers</div>
<div class="text-lg">Stay in the loop with everything you need to know.</div>
</div>
<div class="w-full">
<div class="flex flex-col justify-center sm:flex-row gap-3 w-full">
{{ field }}
<button type="submit" class="sm:w-1/4 h-12 text-white bg-purple-600 rounded-lg shadow transition-all duration-300 ease-in-out hover:bg-purple-700">Subscribe</button>
</div>
<div class="mt-3 text-sm sm:text-center">We care about your data in our <u class="cursor-pointer transition-all duration-300 ease-in-out hover:text-gray-700">privacy policy</u>.</div>
</div>
</div>
</div>
<div> </div>
</div>
</form>
I also have
home/templates/home/form_page_landing.html & home/templates/home/form_page.html
Two template files. The "home/templates/home/form_page_landing.html" is utilised when user "subscribes" by email address, the user is redirected to "home/templates/home/form_page_landing.html" page.
Upvotes: 1
Reputation: 309
After a night's sleep, the answer turned out to be relatively obvious. The missing link is the get_form() method of a Wagtail FormPage. I'm now using this in my TargetPage model:
def attached_form(self):
return self.contact_form.specific.get_form()
And thus, in my template, I can refer to attached_form to get my fields.
Upvotes: 3