Search code examples
djangodjango-cms

Django-CMS CMSPlugin doesn't trigger pre_save/post_save signals


I am trying to add the content of Django-CMS placeholders to the search index (using Algolia, but I guess this could apply for any indexing service, like Elasticsearch or similar) as soon as they are updated.

Using Django 1.10, django-cms 3.42, I have this model (simplified for this question):

from django.db import models
from cms.models.fields import PlaceholderField
from cms.models import CMSPlugin

class NewsItem(models.Model):
    title=models.CharField(_('title'), max_length=200),
    content = PlaceholderField('news_content')

I need to do some extra processing as soon as the model field 'content' is saved, and apparently the best way to check for that is to monitor the CMSPlugin model. So I look for saves using from django.db.models.signals.post_save like this:

@receiver(post_save, sender=CMSPlugin)
def test(sender, **kwargs):
    logger.info("Plugin saved.")

Now, the problem is that post_save is not triggered as I thought it would. With normal CMS Pages, I noticed that post_save is only triggered when a Page is published, but there is no apparent way to publish a placeholder when used outside the CMS.

The closest similar case I've found is Updating indexes on placeholderfields in real time with django/haystack/solr, but the suggested solution doesn't work.

How could I go about resolving this?

Thank you!


Solution

  • We also had the same search indexing problem when we were implementing djangocms-algolia package, since a placeholder update doesn't trigger an update of the index.

    For CMS pages we utilized post_publish and post_unpublish from cms.signals module here.

    And for cms apps that use placeholders (eg djangocms-blog) we attached the listeners to post_placeholder_operation, but beware that to make it work your ModelAdmin needs to inherit from PlaceholderAdminMixin:

    def update_news_index(sender, operation: str, language: str, **kwargs) -> None:
        placeholder: Optional[Placeholder] = None
    
        if operation in (ADD_PLUGIN, DELETE_PLUGIN, CHANGE_PLUGIN, CLEAR_PLACEHOLDER):
            placeholder = kwargs.get('placeholder')
        elif operation in (ADD_PLUGINS_FROM_PLACEHOLDER, PASTE_PLUGIN, PASTE_PLACEHOLDER):
            placeholder = kwargs.get('target_placeholder')
        elif operation in (MOVE_PLUGIN, CUT_PLUGIN):
            placeholder = kwargs.get('source_placeholder')
        else:
            pass
    
        if placeholder:
            post: Post = Post.objects.language(language_code=language).filter(content=placeholder).first()
            if post:
                post.save()
    
    
    signals.post_placeholder_operation.connect(update_news_index, PostAdmin)
    signals.post_placeholder_operation.connect(update_news_index, PageAdmin)