From 6864d684aecae13e041922ca6b15435a0d651237 Mon Sep 17 00:00:00 2001
From: Jonathan Weth <git@jonathanweth.de>
Date: Wed, 11 Mar 2020 15:43:25 +0100
Subject: [PATCH 1/3] Add extensible form which allows to add elements to
 django-material form layouts

---
 aleksis/core/forms.py | 50 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/aleksis/core/forms.py b/aleksis/core/forms.py
index 0daff5fd9..cf6433bfc 100644
--- a/aleksis/core/forms.py
+++ b/aleksis/core/forms.py
@@ -5,15 +5,65 @@ from django import forms
 from django.contrib.auth import get_user_model
 from django.contrib.contenttypes.models import ContentType
 from django.core.exceptions import ValidationError
+from django.forms.models import ModelFormMetaclass
 from django.utils import timezone
 from django.utils.translation import ugettext_lazy as _
 
 from django_select2.forms import ModelSelect2MultipleWidget, Select2Widget
 from material import Layout, Fieldset, Row
+from material.base import LayoutNode
 
 from .models import Group, Person, School, SchoolTerm, Announcement, AnnouncementRecipient
 
 
+class ExtensibleFormMetaclass(ModelFormMetaclass):
+     def __new__(mcs, name, bases, dct):
+        x = super().__new__(mcs, name, bases, dct)
+
+        if hasattr(x, "layout"):
+            base_layout = x.layout.elements
+        else:
+            base_layout = []
+
+        x.base_layout = base_layout
+        x.layout = Layout(*base_layout)
+
+        return x
+
+
+class ExtensibleForm(forms.ModelForm, metaclass=ExtensibleFormMetaclass):
+    """ Base model for extensible forms
+
+    This mixin adds functionality which allows
+    - apps to add layout nodes to the layout used by django-material
+
+    Add layout nodes
+    ================
+
+    ```
+    from material import Fieldset
+
+    from aleksis.core.forms import ExampleForm
+
+    node = Fieldset("field_name")
+    ExampleForm.add_node_to_layout(node)
+    ```
+
+    """
+
+    @classmethod
+    def add_node_to_layout(cls, node: LayoutNode):
+        """
+        Add a node to `layout` attribute
+
+        :param node: django-material layout node (Fieldset, Row etc.)
+        :type node: LayoutNode
+        """
+
+        cls.base_layout.append(node)
+        cls.layout = Layout(*cls.base_layout)
+
+
 class PersonAccountForm(forms.ModelForm):
     class Meta:
         model = Person
-- 
GitLab


From e4e1d9b163de24032fa0d1505a4d92cc18a5e193 Mon Sep 17 00:00:00 2001
From: Jonathan Weth <git@jonathanweth.de>
Date: Thu, 12 Mar 2020 11:08:33 +0100
Subject: [PATCH 2/3] Move ExtensibleForm to mixins.py

---
 aleksis/core/forms.py  | 50 ------------------------------------------
 aleksis/core/mixins.py | 50 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+), 50 deletions(-)

diff --git a/aleksis/core/forms.py b/aleksis/core/forms.py
index cf6433bfc..0daff5fd9 100644
--- a/aleksis/core/forms.py
+++ b/aleksis/core/forms.py
@@ -5,65 +5,15 @@ from django import forms
 from django.contrib.auth import get_user_model
 from django.contrib.contenttypes.models import ContentType
 from django.core.exceptions import ValidationError
-from django.forms.models import ModelFormMetaclass
 from django.utils import timezone
 from django.utils.translation import ugettext_lazy as _
 
 from django_select2.forms import ModelSelect2MultipleWidget, Select2Widget
 from material import Layout, Fieldset, Row
-from material.base import LayoutNode
 
 from .models import Group, Person, School, SchoolTerm, Announcement, AnnouncementRecipient
 
 
-class ExtensibleFormMetaclass(ModelFormMetaclass):
-     def __new__(mcs, name, bases, dct):
-        x = super().__new__(mcs, name, bases, dct)
-
-        if hasattr(x, "layout"):
-            base_layout = x.layout.elements
-        else:
-            base_layout = []
-
-        x.base_layout = base_layout
-        x.layout = Layout(*base_layout)
-
-        return x
-
-
-class ExtensibleForm(forms.ModelForm, metaclass=ExtensibleFormMetaclass):
-    """ Base model for extensible forms
-
-    This mixin adds functionality which allows
-    - apps to add layout nodes to the layout used by django-material
-
-    Add layout nodes
-    ================
-
-    ```
-    from material import Fieldset
-
-    from aleksis.core.forms import ExampleForm
-
-    node = Fieldset("field_name")
-    ExampleForm.add_node_to_layout(node)
-    ```
-
-    """
-
-    @classmethod
-    def add_node_to_layout(cls, node: LayoutNode):
-        """
-        Add a node to `layout` attribute
-
-        :param node: django-material layout node (Fieldset, Row etc.)
-        :type node: LayoutNode
-        """
-
-        cls.base_layout.append(node)
-        cls.layout = Layout(*cls.base_layout)
-
-
 class PersonAccountForm(forms.ModelForm):
     class Meta:
         model = Person
diff --git a/aleksis/core/mixins.py b/aleksis/core/mixins.py
index 984a41255..f921ae4e8 100644
--- a/aleksis/core/mixins.py
+++ b/aleksis/core/mixins.py
@@ -4,9 +4,11 @@ from typing import Any, Callable, Optional
 from django.contrib.contenttypes.models import ContentType
 from django.db import models
 from django.db.models import QuerySet
+from django.forms.models import ModelFormMetaclass, ModelForm
 
 from easyaudit.models import CRUDEvent
 from jsonstore.fields import JSONField, JSONFieldMixin
+from material.base import LayoutNode, Layout
 
 
 class CRUDMixin(models.Model):
@@ -170,3 +172,51 @@ class ExtensibleModel(CRUDMixin):
 class PureDjangoModel(object):
     """ No-op mixin to mark a model as deliberately not using ExtensibleModel """
     pass
+
+
+class ExtensibleFormMetaclass(ModelFormMetaclass):
+    def __new__(mcs, name, bases, dct):
+        x = super().__new__(mcs, name, bases, dct)
+
+        if hasattr(x, "layout"):
+            base_layout = x.layout.elements
+        else:
+            base_layout = []
+
+        x.base_layout = base_layout
+        x.layout = Layout(*base_layout)
+
+        return x
+
+
+class ExtensibleForm(ModelForm, metaclass=ExtensibleFormMetaclass):
+    """ Base model for extensible forms
+
+    This mixin adds functionality which allows
+    - apps to add layout nodes to the layout used by django-material
+
+    Add layout nodes
+    ================
+
+    ```
+    from material import Fieldset
+
+    from aleksis.core.forms import ExampleForm
+
+    node = Fieldset("field_name")
+    ExampleForm.add_node_to_layout(node)
+    ```
+
+    """
+
+    @classmethod
+    def add_node_to_layout(cls, node: LayoutNode):
+        """
+        Add a node to `layout` attribute
+
+        :param node: django-material layout node (Fieldset, Row etc.)
+        :type node: LayoutNode
+        """
+
+        cls.base_layout.append(node)
+        cls.layout = Layout(*cls.base_layout)
-- 
GitLab


From d48104e4e1df5481863a5878aad3a5a8700f4b84 Mon Sep 17 00:00:00 2001
From: Jonathan Weth <git@jonathanweth.de>
Date: Thu, 12 Mar 2020 20:09:33 +0100
Subject: [PATCH 3/3] Make ExtensibleFormMetaclass private

---
 aleksis/core/mixins.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/aleksis/core/mixins.py b/aleksis/core/mixins.py
index f921ae4e8..c034717c5 100644
--- a/aleksis/core/mixins.py
+++ b/aleksis/core/mixins.py
@@ -174,7 +174,7 @@ class PureDjangoModel(object):
     pass
 
 
-class ExtensibleFormMetaclass(ModelFormMetaclass):
+class _ExtensibleFormMetaclass(ModelFormMetaclass):
     def __new__(mcs, name, bases, dct):
         x = super().__new__(mcs, name, bases, dct)
 
@@ -189,7 +189,7 @@ class ExtensibleFormMetaclass(ModelFormMetaclass):
         return x
 
 
-class ExtensibleForm(ModelForm, metaclass=ExtensibleFormMetaclass):
+class ExtensibleForm(ModelForm, metaclass=_ExtensibleFormMetaclass):
     """ Base model for extensible forms
 
     This mixin adds functionality which allows
-- 
GitLab