Created
March 15, 2019 16:17
-
-
Save philgyford/c6e7064207aeddf12b2791a3f86335af to your computer and use it in GitHub Desktop.
Example of how to add a form to every instance of a type of Wagtail CMS Page, without having to manually build the page for each new page in the Admin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{% extends "base.html" %} | |
{% block content %} | |
<p>(Article content here.)</p> | |
<p>Send us your thoughts:</p> | |
<form action="{% pageurl page %}" method="POST"> | |
{% csrf_token %} | |
{{ form.as_p }} | |
<input type="submit" value="Send"> | |
</form> | |
{% endblock content %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{% extends "base.html" %} | |
{% block content %} | |
<p>Thanks for your thoughts!</p> | |
<p><a href="{{ page.url }}">Return to “{{ page.title }}”</a></p> | |
{% endblock content %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.core.exceptions import ValidationError | |
from django.db import models | |
from modelcluster.fields import ParentalKey | |
from wagtail.contrib.forms.models import AbstractEmailForm, AbstractFormField | |
# All of this is so that we can automatically generate a form on every | |
# ArticlePage, and don't have to create it manually in the Wagtail | |
# Admin for each one. | |
# | |
# This inspired by https://stackoverflow.com/a/47303659/250962 | |
# The fields that will be on the form on each ArticlePage. | |
# | |
# field_type can only be one of the following: | |
# | |
# 'singleline', 'multiline', 'email', 'number', 'url', 'checkbox', | |
# 'checkboxes', 'dropdown', 'multiselect', 'radio', 'date', | |
# 'datetime', 'hidden' | |
# | |
# Important: Label MUST be unique in each form | |
# | |
# Should be in the correct order for the form: | |
ARTICLE_FORM_FIELDS = [ | |
{ | |
'label': 'Your comments', | |
'field_type': 'multiline', | |
'required': True, | |
}, | |
{ | |
'label': 'Your name', | |
'field_type': 'singleline', | |
'required': False, | |
}, | |
{ | |
'label': 'Your email', | |
'field_type': 'email', | |
'required': False, | |
}, | |
] | |
RESERVED_LABELS = [field['label'] for field in ARTICLE_FORM_FIELDS] | |
def validate_label(value): | |
"Ensure we have no duplicates." | |
if value in RESERVED_LABELS: | |
raise ValidationError("'%s' is reserved." % value) | |
class ArticleFormField(AbstractFormField): | |
"""For creating the fields on a ArticlePage's form. | |
These are all created in ArticleEmailForm.get_form_fields(), rather | |
than in the Wagtail admin. | |
""" | |
page = ParentalKey('ArticlePage', | |
on_delete=models.CASCADE, | |
related_name='form_fields') | |
# Redefine 'label' field so we can ensure there will be no conflicts with | |
# constant fields | |
label = models.CharField( | |
verbose_name='label', | |
max_length=255, | |
help_text='The label of the form field, cannot be one of the following: %s.' | |
% ', '.join(RESERVED_LABELS), | |
validators=[validate_label] | |
) | |
class ArticleEmailForm(AbstractEmailForm): | |
"""Extending AbstractEmailForm to add our customm extra fields, so that | |
they don't have to be defined afresh when creating every ArticlePage. | |
ArticlePage should inherit from this. | |
We're putting all the form-related stuff here so that it's kept separate | |
from the more general Page-related stuff. | |
""" | |
# Redefine the to_address, from_address and subject so that they don't have | |
# to be entered for every new ArticlePage. | |
subject = "Comment about an Article" | |
@property | |
def to_address(self): | |
"""Get the email's 'to' address. You may want to set this somewhere | |
more useful, in a setting. | |
""" | |
return "[email protected]" | |
@property | |
def from_address(self): | |
"""Get the email's 'from' address. You may want to set this somewhere | |
more useful, in a setting. | |
""" | |
return "[email protected]" | |
def get_form_fields(self): | |
"""Add to the parent's get_foro_fields() to add our hard-coded | |
field | |
""" | |
fields = list(super().get_form_fields()) | |
# Append instances of ArticleFormField - not actually stored in the db | |
# `insert(0` will prepend these items, so the last added will be first | |
for field in reversed(ARTICLE_FORM_FIELDS): | |
fields.insert(0, | |
ArticleFormField( | |
label=field['label'], | |
field_type=field['field_type'], | |
required=field['required'] | |
) | |
) | |
return fields | |
class Meta: | |
abstract = True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from wagtail.core.models import Page | |
from forms import ArticleEmailForm | |
class ArticlePage(ArticleEmailForm, Page): | |
template = "article.html" | |
landing_page_template = "article_landing.html" | |
# More here... |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment