from django import forms from django.forms.forms import DeclarativeFieldsMetaclass from wagtail.contrib.forms.forms import BaseForm class MixedFieldMetaclass(DeclarativeFieldsMetaclass): """Stores all fields passed to the class and not just the field type. This allows the form to be rendered when Field-like blocks are passed in as part of the definition """ def __new__(mcs, name, bases, attrs): display = attrs.copy() new_class = super(MixedFieldMetaclass, mcs).__new__(mcs, name, bases, attrs) new_class.display = display return new_class class StreamBaseForm(forms.Form, metaclass=MixedFieldMetaclass): def swap_fields_for_display(func): def wrapped(self, *args, **kwargs): # Replaces the form fields with the display fields # should only add new streamblocks and wont affect validation fields = self.fields.copy() self.fields = self.display yield from func(self, *args, **kwargs) self.fields = fields return wrapped @swap_fields_for_display def __iter__(self): yield from super().__iter__() @swap_fields_for_display def _html_output(self, *args, **kwargs): return super()._html_output(*args, **kwargs) class PageStreamBaseForm(BaseForm, StreamBaseForm): # Adds page and user reference to the form class pass class BlockFieldWrapper: """Wraps stream blocks so that they can be rendered as a field within a form""" is_hidden = False label = None help_text = None def __init__(self, block): self.block = block def get_bound_field(self, *args, **kwargs): return self def css_classes(self): return list() @property def errors(self): return list() @property def html_name(self): return self.block.id def __str__(self): return str(self.block.value)