Default children plugins on custom plugin

I have a custom plugin called MultiColumnResponsive that receives the number of columns as parameter and accepts ColumnResponsive plugin only as children. I want to create the ColumnResponsive plugins nested as children by default, but I am not able to do it.

Here my current code:

cms_plugins.py

class MultiColumnResponsivePlugin(CMSPluginBase):
    name = "Multi Column Responsive"
    module = _("Containers")
    model = MultiColumn
    render_template = "plugin/multi-column-responsive/multi-column-responsive.html"
    allow_children = True
    child_classes = ["ColumnResponsivePlugin"]

    def render(self, context, instance, placeholder):
        context = super(MultiColumnResponsivePlugin, self).render(context, instance, placeholder)
        return context

class ColumnResponsivePlugin(CMSPluginBase):
    name = "Column Responsive"
    module = _("Containers")
    render_template = "plugin/column-responsive/column-responsive.html"
    allow_children = True
    parent_classes = ["MultiColumnResponsivePlugin"]

    def render(self, context, instance, placeholder):
        context = super(ColumnResponsivePlugin, self).render(context, instance, placeholder)
        return context

models.py

class MultiColumn(CMSPlugin):
    NUM_OF_COLUMNS = (
        (1, '1'),
        (2, '2'),
    )
    num_of_columns = models.IntegerField(default=1, choices=NUM_OF_COLUMNS)

This is the desire result when I add a MultiColumnResponsive plugin with 2 columns:

enter image description here

EDIT: After several days digging into it. I achieved it adding a few lines in the save_model function in the MultiColumnResponsivePlugin class:

def save_model(self, request, obj, form, change):
    response = super(MultiColumnResponsivePlugin, self).save_model(
        request, obj, form, change
    )
    for x in range(int(form.cleaned_data['num_of_columns'])):
        add_plugin(obj.placeholder, ColumnResponsivePlugin.__name__, obj.language, target=obj)
    return response

Upvotes: 1

Views: 543

Answers (1)

jrief
jrief

Reputation: 1695

You can try this:

from django.forms import ModelForm, NumberInput
from cms.api import add_plugin

class MultiColumnResponsiveForm(ModelForm):
    wanted_children = NumberInput()

    class Meta:
        model = MultiColumn
        fields = '__all__'

class MultiColumnResponsivePlugin(CMSPluginBase):
    name = "Multi Column Responsive"
    module = _("Containers")
    model = MultiColumn
    render_template = "plugin/multi-column-responsive/multi-column-responsive.html"
    allow_children = True
    child_classes = ["ColumnResponsivePlugin"]
    form = MultiColumnResponsiveForm

    def save_model(self, request, obj, form, change):
        wanted_children = form.cleaned_data['wanted_children']
        super().save_model(request, obj, form, change)
        self.extend_children(obj, wanted_children)

    def extend_children(self, parent, wanted_children):
        current_children = parent.get_num_children()
        for _ in range(current_children, wanted_children):
            child = add_plugin(parent.placeholder, ColumnResponsivePlugin,
                               parent.language, target=parent)
            child.save()

Some notes on this:

If you need a temporary value such as wanted_children, use a form and do not pollute your model!

This code snippet is an adoption from djangocms-cascade, which uses a similar approach to achieve the same result.

Upvotes: 2

Related Questions