djangocms custom plugin duplicating behavior

277 Views Asked by At

I have a simple custom djangocms plugin that acts strangely upon publishing changes.

The full code is in this repo: https://github.com/creimers/djangocms_sociallist

This is the model:

class SocialList(CMSPlugin):

    name = models.CharField(
        'Liste',
        blank=False,
        default='',
        max_length=32,
    )

def copy_relations(self, oldinstance):
    for associated_item in oldinstance.associated_item.all():
        associated_item.pk = None
        associated_item.plugin = self
        associated_item.save()

def __unicode__(self):
    return u'%s' % self.name


class SocialIcon(models.Model):
    choices = (
        ('fa-facebook', 'facebook'),
        ('fa-google-plus', 'google-plus'),
        ('fa-twitter', 'twitter'),
        ('fa-instagram', 'instagram'),
        ('fa-yelp', 'yelp'),
        ('fa-youtube-play', 'youtube'),
        ('fa-foursquare', 'foursquare'),
    )
    social_list = models.ForeignKey(
        SocialList,
        related_name="associated_item"
    )
    icon = models.CharField(
        max_length=200,
        blank=False,
        choices=choices,
    )
    link = models.URLField(
        max_length=200,
        blank=False
    )

    def __unicode__(self):
        return u'%s' % self.icon

This is the cms_plugins.py:

class ChoiceInline(admin.TabularInline):
    model = SocialIcon
    extra = 1


class SocialPlugin(CMSPluginBase):
    name = u'Social Icons'
    model = SocialList
    render_template = "djangocms_sociallist/_social_plugin.html"
    #form = SocialListPluginAdminForm
    inlines = [ChoiceInline, ]

    def render(self, context, instance, placeholder):
        items = instance.associated_item.all()
        context.update({
            'items': items,
            'instance': instance,
        })
        return context

plugin_pool.register_plugin(SocialPlugin)

And this is the template:

<div class="social-list-container">
    <ul class="social-list">
        {% for icon in items %}
        <a href="{{icon.link}}">
            <li class="social-list-item">
                <i class="fa {{icon.icon}}"></i>
            </li>
        </a>
        {% endfor %}
    </ul>
</div>

In draft mode, everything works as I'd expect. Strange things happen when I hit 'publish changes'.

This is in draft mode. I have added three icons. The icon list is called 'test' and can be seen in the left admin sidebar.

DRAFT MODE

Then, after switching to 'live', the icons don't show. Also, the 'test' list has duplicated in the admin panel.

LIVE MODE

Switching back to 'draft', the two lists with the same name are rendered in the plugin template.

BACK TO DRAFT

Admittedly new to django(cms) and its concepts, I don't quite know what to make of this. Does anyone have an idea?

1

There are 1 best solutions below

0
On

I can give a partial answer to my question:

associated_item.plugin = self should have been associated_item.social_list = self, of course. I simply forgot to plug in the name of my specific model reference.

So this is what my copy_relations looks like now:

def copy_relations(self, oldinstance):
    for associated_item in oldinstance.associated_item.all():
        associated_item.pk = None
        associated_item.social_list = self
        associated_item.save()

I can now publish my plugin and it doesn't disappear.

Concerning the duplicating behavior:

The issue I think is that I've been messing where I shouldn't have been messing.

I take the same model (inheriting from CMSPlugin) and reference it both in admin.py and cms_plugins.py. Instead, I think I should have done something like this:

class SocialList(models.Model):

    name = models.CharField(
        'Liste',
        blank=False,
        default='',
        max_length=32,
    )

    def copy_relations(self, oldinstance):
        for associated_item in oldinstance.associated_item.all():
            associated_item.pk = None
            associated_item.social_list = self
            associated_item.save()

    def __unicode__(self):
        return u'%s' % self.name

    class SocialListPlugin(CMSPlugin):

        list = models.ForeignKey(SocialList)

        def __unicode__(self):
            return u'%s' % self.list.name

Hence a separation of concerns.

That's my conclusion after digging through other peoples plugins on github and analyzing how they bind models to admin and cms_plugins. Please correct me if I'm wrong.