Repository: wagtail/wagtail

Issue:
Change AbstractForm to a mixin class called FormPageMixin
- Since AbstractForm inherited from Page, any custom Page subclass couldn't use it.
- Changing it to a mixin allows subclasses of Page to gain Form Builder.
### TODO
- ~~Write tests~~
### Testing
- Run tests: `python runtests.py wagtail.wagtailforms`
- Create a Page class that inherits from Page and the mixin with the form fields related and the appropriate template files made:

``` python
from modelcluster.fields import ParentalKey
from wagtail.wagtailcore.models import Page
from wagtail.wagtailforms.models import FormPageMixin, AbstractFormField

class FormField(AbstractFormField):
    page = ParentalKey('FormPage', related_name='form_fields')

class FormPage(FormPageMixin, Page):
    content_panels = Page.content_panels + [
        InlinePanel('form_fields', label="Form fields")
    ]
```
- Create migration file, run the migration, and login to the admin
- Add a page with fields and test the page to make sure it submits properly.
### Other notes

This spawned from a discussion on [this thread](https://groups.google.com/forum/#!topic/wagtail-developers/K4_LGKzO8gE) where @gasman encouraged a pull request for it.



Discussion:

Resolving patch:
diff --git a/wagtail/contrib/forms/models.py b/wagtail/contrib/forms/models.py
--- a/wagtail/contrib/forms/models.py
+++ b/wagtail/contrib/forms/models.py
@@ -152,10 +152,8 @@ class Meta:
         ordering = ["sort_order"]
 
 
-class AbstractForm(Page):
-    """
-    A Form Page. Pages implementing a form should inherit from it
-    """
+class FormMixin:
+    """A mixin that adds form builder functionality to the page."""
 
     base_form_class = WagtailAdminFormPageForm
 
@@ -169,9 +167,6 @@ def __init__(self, *args, **kwargs):
             name, ext = os.path.splitext(self.template)
             self.landing_page_template = name + "_landing" + ext
 
-    class Meta:
-        abstract = True
-
     def get_form_fields(self):
         """
         Form page expects `form_fields` to be declared.
@@ -209,7 +204,7 @@ def get_form(self, *args, **kwargs):
 
         return form_class(*args, **form_params)
 
-    def get_landing_page_template(self, request, *args, **kwargs):
+    def get_landing_page_template(self, *args, **kwargs):
         return self.landing_page_template
 
     def get_submission_class(self):
@@ -299,17 +294,23 @@ def validate_to_address(value):
         validate_email(address.strip())
 
 
-class AbstractEmailForm(AbstractForm):
-    """
-    A Form Page that sends email. Pages implementing a form to be send to an email should inherit from it
-    """
+class AbstractForm(FormMixin, Page):
+    """A Form Page. Pages implementing a form should inherit from it."""
+
+    class Meta:
+        abstract = True
+
+
+class EmailFormMixin(models.Model):
+    """A mixin that adds email sending functionality to the form."""
 
     to_address = models.CharField(
         verbose_name=_("to address"),
         max_length=255,
         blank=True,
         help_text=_(
-            "Optional - form submissions will be emailed to these addresses. Separate multiple addresses by comma."
+            "Optional - form submissions will be emailed to these addresses. "
+            "Separate multiple addresses by comma."
         ),
         validators=[validate_to_address],
     )
@@ -346,7 +347,7 @@ def render_email(self, form):
             if isinstance(value, list):
                 value = ", ".join(value)
 
-            # Format dates and datetimes with SHORT_DATE(TIME)_FORMAT
+            # Format dates and datetime(s) with SHORT_DATE(TIME)_FORMAT
             if isinstance(value, datetime.datetime):
                 value = date_format(value, settings.SHORT_DATETIME_FORMAT)
             elif isinstance(value, datetime.date):
@@ -358,3 +359,12 @@ def render_email(self, form):
 
     class Meta:
         abstract = True
+
+
+class AbstractEmailForm(EmailFormMixin, FormMixin, Page):
+    """
+    A Form Page that sends email. Inherit from it if your form sends an email.
+    """
+
+    class Meta:
+        abstract = True
diff --git a/wagtail/contrib/forms/utils.py b/wagtail/contrib/forms/utils.py
--- a/wagtail/contrib/forms/utils.py
+++ b/wagtail/contrib/forms/utils.py
@@ -18,10 +18,10 @@ def get_field_clean_name(label):
 def get_form_types():
     global _FORM_CONTENT_TYPES
     if _FORM_CONTENT_TYPES is None:
-        from wagtail.contrib.forms.models import AbstractForm
+        from wagtail.contrib.forms.models import FormMixin
 
         form_models = [
-            model for model in get_page_models() if issubclass(model, AbstractForm)
+            model for model in get_page_models() if issubclass(model, FormMixin)
         ]
 
         _FORM_CONTENT_TYPES = list(


Test patch: