====================== django-cms-facetsearch ====================== This package provides multilingual search indexes for easy Haystack integration with `django CMS `_. Usage ===== After installing django-cms-facetsearch through your package manager of choice, add :mod:`cms_facetsearch` to your :setting:`INSTALLED_APPS`. That's it. For setting up Haystack using solr as needed for faceting, please refer to their `documentation `_. Customizing the Index --------------------- You can customize what parts of a :class:`~cms.models.CMSPlugin` end up in the index with two class attributes on :class:`~cms.models.CMSPlugin` subclasses: .. attribute:: search_fields a list of field names to index. .. attribute:: search_fulltext if ``True``, the index renders the plugin and adds the result (sans HTML tags) to the index. Using with django-cms apphooks ------------------------------- Add the `Django Cms Faceted Search` apphook to a page. Indexes ======= .. module:: cms_facetsearch.indexes django-cms-search provides a couple of useful helpers to deal with multilingual content. .. py:class:: cms_facetsearch.indexes.TranslationIndex A :class:`~haystack:SearchIndex` that adds a prepare_translated method and a faceted language field to the search index. An example for when this is useful is the app hook infrastructure from django CMS. When a model's :meth:`~django.db.models.Model.get_absolute_url` uses a url pattern that is attached to an app hook and there is a own model for titles per language the URL varies depending on the language or ay translated strings. A usage example: .. code-block:: python # models.py class Story(models.Model): pub_date = models.DateTimeField(default=datetime.datetime.now) class StoryTitle(models.Model): story = models.ForeignKey(Story) language = models.CharField(max_length=15, choices=settings.LANGUAGES) title = models.CharField(max_length=255) slug = models.SlugField() def _get_absolute_url(self): return ('%sstory_detail' % self.language, (), { 'year': self.story.pub_date.strftime('%Y'), 'month': self.story.pub_date.strftime('%m'), 'day': self.story.pub_date.strftime('%d'), 'slug': self.slug }) get_absolute_url = models.permalink(_get_absolute_url) # search_indexes.py from models import StoryTitle from haystack import indexes, site from cms_facetsearch.indexes import TranslationIndex class StoryTitleIndex(TranslationIndex): text = indexes.CharField(document=True, use_template=True) title = indexes.CharField(model_attr='title') url = indexes.CharField(stored=True) def prepare_translated(self, obj, language): data = super(StoryTitleIndex, self).prepare_translated(self, obj, language) data['url'] = obj.get_absolute_url() return data site.register(StoryTitle, StoryTitleIndex) .. note:: * In the above example, you might want to catch :class:`~django.core.urlresolvers.NoReverseMatch` exceptions if you don't have activated the app hook for all languages defined in :setting:`django:LANGUAGES`. .. note:: django CMS monkeypatches :func:`django.core.urlresolvers.reverse` to enable language namespaces. To ensure that this monkeypatching happens before haystack autodiscovers your indexes, your ``search_sites.py`` should look somewhat like this, will be fixed to work properly in django-cms 2.2: .. code-block:: python from cms.models import monkeypatch_reverse import haystack monkeypatch_reverse() haystack.autodiscover() .. py:class:: cms_facetsearch.indexes.PluginIndex A :class:`~cms_facetsearch:TranslationIndex` subclass that renders plugins from for a specific language as a document CharField for all placeholdes related to the model. A usage example: .. code-block:: python # models.py from cms.models.fields import PlaceholderField # or from djangocms_utils.fields import M2MPlaceholderField class Story(models.Model): pub_date = models.DateTimeField(default=datetime.datetime.now) placeholder = PlaceholderField() class StoryTitle(models.Model): story = models.ForeignKey(Story) language = models.CharField(max_length=15, choices=settings.LANGUAGES) title = models.CharField(max_length=255) slug = models.SlugField() # search_indexes.py from models import StoryTitle from haystack import indexes, site from cms_facetsearch.indexes import PluginIndex class StoryTitleIndex(PluginIndex): title = indexes.CharField(model_attr='title') url = indexes.CharField(stored=True) def get_placeholders(self, obj, language): return [obj.story.placeholder] site.register(StoryTitle, StoryTitleIndex) Advanced ======== The current development version of ``django-cms-facetsearch`` supports ``haystack-celery`` so you can update the index when saving the model you want to index or a plugin related to the model you want to index. All you need to do to activate this is to set up ``django-celery`` and add ``haystack_celery`` to ``INSTALLED_APPS``. Finding the model related to the plugins requires a extara hook ``get_index_instance_from_plugin``to query for the instance. The search_index for the Django CMS pages and cmsplugin-blog already has this method defined. .. code-block:: python # models.py from cms.models.fields import PlaceholderField # or from djangocms_utils.fields import M2MPlaceholderField class Story(models.Model): pub_date = models.DateTimeField(default=datetime.datetime.now) placeholder = PlaceholderField() class StoryTitle(models.Model): story = models.ForeignKey(Story) language = models.CharField(max_length=15, choices=settings.LANGUAGES) title = models.CharField(max_length=255) slug = models.SlugField() from models import StoryTitle from haystack import indexes, site from cms_facetsearch.indexes import PluginIndex class StoryTitleIndex(PluginIndex): title = indexes.CharField(model_attr='title') url = indexes.CharField(stored=True) def get_placeholders(self, obj, language): return [obj.story.placeholder] def get_index_instance_from_plugin(self, instance, **kwargs): try: return StoryTitle.objects.get(story__placeholder__cmsplugin=instance) except StoryTitle.DoesNotExist: return None site.register(StoryTitle, StoryTitleIndex) Settings ======== .. setting: CMS_FACETSEARCH_REGISTER_SEARCHINDEX CMS_FACETSEARCH_REGISTER_SEARCHINDEX ------------------------------------ Default: :boolean:`True` This setting can be used to disable registering of django-cms Titles with a :class:`~cms_facetsearch:PluginIndex` if you use another search solution for cms core. .. setting: CMS_FACETSEARCH_LABEL_OVERRIDES CMS_FACETSEARCH_LABEL_OVERRIDES ------------------------------- Default: :dict:`{}` This setting can be used to change the labels for model selection in the search form Eg. CMS_FACETSEARCH_LABEL_OVERRIDES={'news.storytitle': gettext('Stories') }