lunedì 29 giugno 2015

django-cms and haystack: update index with a django signal

Haystack provides the HAYSTACK_SIGNAL_PROCESSOR settings and it works well, especially the RealtimeSignalProcessor for the django models.

But, the problem that I had was update the search index when the user publishes a django-cms page.
In fact, if you use the HAYSTACK_SIGNAL_PROCESSOR settings, haystack will update your index with the draft copy of the page - both if you save a plugin or a page itself - and it's not a good thing for user experience... and also for our indexes! :-)

Going deep into this issue, I wrote a signal that wraps the RealtimeSignalProcessor and that doesn't break the django-cms publish command if there's no connection to the search engine.

# models.py
# other imports
import logging
# ...
logger = logging.getLogger(__name__)
# ...

def real_time_signal_processor(instance, **kwargs):
    from elasticsearch.exceptions import ConnectionError
    from django.conf import settings
    from haystack import signals
    from haystack.utils import loading

    connections = loading.ConnectionHandler(settings.HAYSTACK_CONNECTIONS)
    connection_router = loading.ConnectionRouter()
    if hasattr(settings, 'HAYSTACK_ROUTERS'):
        connection_router = loading.ConnectionRouter(settings.HAYSTACK_ROUTERS)
    try:
        signals.RealtimeSignalProcessor(connections, connection_router).handle_save(kwargs['sender'], instance)
    except ConnectionError as e:
        logger.error(e.message)


post_publish.connect(real_time_signal_processor)

Just for curiosity, the models.py is a part of the django app named search, where I put all the search engine code (custom backends, forms, etc). I think it's a good practice and nice to have an isolated app that serve to search purposes.

That's it!

Cheers

[Update] The code above catch the exception from elasticsearch client. With a generic exception, you can use that signal with your search backend. IMHO is not a good practice to catch a generic Exception, then use the appropriate one! :-)

Nessun commento: