From 3d6e2e3b323d7622b7cb9b0d1f2a77272a100c1b Mon Sep 17 00:00:00 2001 From: Iacopo Spalletti Date: Sun, 21 Jun 2020 15:37:31 +0200 Subject: [PATCH] Skip haystack index creation if aldryn-search is not installed (#585) * Skip haystack index creation if aldryn-search is not installed but haystack is --- .github/workflows/test.yml | 4 + changes/584.bugfix | 1 + cms_helper.py | 9 +- djangocms_blog/search_indexes.py | 160 ++++++++++++++++--------------- docs/installation.rst | 2 + requirements-test.txt | 1 - tests/test_indexing.py | 33 ++++++- tox.ini | 7 +- 8 files changed, 134 insertions(+), 83 deletions(-) create mode 100644 changes/584.bugfix diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 52f86c20..dd90881a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -51,6 +51,10 @@ jobs: exclude: - python-version: 3.5 django: 30 + include: + - python-version: 3.8 + django: 22 + cms: no-search-37 steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} diff --git a/changes/584.bugfix b/changes/584.bugfix new file mode 100644 index 00000000..150e0dda --- /dev/null +++ b/changes/584.bugfix @@ -0,0 +1 @@ +Skip haystack index creation if aldryn-search is not installed but haystack is diff --git a/cms_helper.py b/cms_helper.py index a5aab74d..4053d2d9 100755 --- a/cms_helper.py +++ b/cms_helper.py @@ -21,7 +21,6 @@ def gettext(s): "taggit", "taggit_autosuggest", "aldryn_apphooks_config", - "aldryn_search", "djangocms_video", "sortedm2m", "tests.media_app", @@ -79,6 +78,14 @@ def gettext(s): } except ImportError: pass + + +try: + import aldryn_search # pragma: no cover # NOQA + + HELPER_SETTINGS["INSTALLED_APPS"].append("aldryn_search") +except ImportError: + pass os.environ["AUTH_USER_MODEL"] = "tests.test_utils.CustomUser" if "server" in sys.argv[:3]: diff --git a/djangocms_blog/search_indexes.py b/djangocms_blog/search_indexes.py index bf0e629c..f7b688bb 100644 --- a/djangocms_blog/search_indexes.py +++ b/djangocms_blog/search_indexes.py @@ -1,78 +1,82 @@ -from aldryn_search.helpers import get_plugin_index_data -from aldryn_search.utils import get_index_base, strip_tags -from django.utils.encoding import force_str -from haystack import indexes -from parler.utils.context import switch_language - -from .models import Post -from .settings import get_setting - - -class PostIndex(get_index_base()): - haystack_use_for_indexing = get_setting("ENABLE_SEARCH") - - index_title = True - - author = indexes.CharField(indexed=True, model_attr="get_author") - keywords = indexes.CharField(null=True) - tags = indexes.CharField(null=True, model_attr="get_tags") - post_text = indexes.CharField(null=True) - - def get_title(self, post): - return post.get_title() - - def get_description(self, post): - return post.get_description() - - def prepare_pub_date(self, post): - return post.date_published - - def index_queryset(self, using=None): - self._get_backend(using) - language = self.get_current_language(using) - filter_kwargs = self.get_index_kwargs(language) - qs = self.get_index_queryset(language) - if filter_kwargs: - return qs.translated(language, **filter_kwargs) - return qs - - def get_index_queryset(self, language): - return self.get_model().objects.published().active_translations(language_code=language) - - def get_model(self): - return Post - - def get_search_data(self, post, language, request): - with switch_language(post, language): - description = post.get_description() - abstract = strip_tags(post.safe_translation_getter("abstract", default="")) - keywords = post.get_keywords() - - text_bits = [] - if abstract: - text_bits.append(abstract) - if description: - text_bits.append(description) - if keywords: - text_bits.append(" ".join(keywords)) - self.prepared_data["keywords"] = ",".join(keywords) - for category in post.categories.all(): - text_bits.append(force_str(category.safe_translation_getter("name"))) - for tag in post.tags.all(): - text_bits.append(force_str(tag.name)) - - if get_setting("USE_PLACEHOLDER"): - plugins = post.content.cmsplugin_set.filter(language=language) - content_bits = [] - for base_plugin in plugins: - content = get_plugin_index_data(base_plugin, request) - content_bits.append(" ".join(content)) - post_text = " ".join(content_bits) - else: - post_text = post.safe_translation_getter("post_text") - if post_text: - post_text = strip_tags(post_text) - self.prepared_data["post_text"] = post_text - text_bits.append(post_text) - - return " ".join(text_bits) +try: + from aldryn_search.helpers import get_plugin_index_data + from aldryn_search.utils import get_index_base, strip_tags + from django.utils.encoding import force_str + from haystack import indexes + from parler.utils.context import switch_language + + from .models import Post + from .settings import get_setting + + class PostIndex(get_index_base()): + haystack_use_for_indexing = get_setting("ENABLE_SEARCH") + + index_title = True + + author = indexes.CharField(indexed=True, model_attr="get_author") + keywords = indexes.CharField(null=True) + tags = indexes.CharField(null=True, model_attr="get_tags") + post_text = indexes.CharField(null=True) + + def get_title(self, post): + return post.get_title() + + def get_description(self, post): + return post.get_description() + + def prepare_pub_date(self, post): + return post.date_published + + def index_queryset(self, using=None): + self._get_backend(using) + language = self.get_current_language(using) + filter_kwargs = self.get_index_kwargs(language) + qs = self.get_index_queryset(language) + if filter_kwargs: + return qs.translated(language, **filter_kwargs) + return qs + + def get_index_queryset(self, language): + return self.get_model().objects.published().active_translations(language_code=language) + + def get_model(self): + return Post + + def get_search_data(self, post, language, request): + with switch_language(post, language): + description = post.get_description() + abstract = strip_tags(post.safe_translation_getter("abstract", default="")) + keywords = post.get_keywords() + + text_bits = [] + if abstract: + text_bits.append(abstract) + if description: + text_bits.append(description) + if keywords: + text_bits.append(" ".join(keywords)) + self.prepared_data["keywords"] = ",".join(keywords) + for category in post.categories.all(): + text_bits.append(force_str(category.safe_translation_getter("name"))) + for tag in post.tags.all(): + text_bits.append(force_str(tag.name)) + + if get_setting("USE_PLACEHOLDER"): + plugins = post.content.cmsplugin_set.filter(language=language) + content_bits = [] + for base_plugin in plugins: + content = get_plugin_index_data(base_plugin, request) + content_bits.append(" ".join(content)) + post_text = " ".join(content_bits) + else: + post_text = post.safe_translation_getter("post_text") + if post_text: + post_text = strip_tags(post_text) + self.prepared_data["post_text"] = post_text + text_bits.append(post_text) + + return " ".join(text_bits) + + +except ImportError: + pass diff --git a/docs/installation.rst b/docs/installation.rst index 828b523d..680e836e 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -49,6 +49,8 @@ If you want to enable haystack support, in addition to the above: * add ``aldryn_search`` to ``INSTALLED_APPS`` * configure haystack according to `aldryn-search docs `_ and `haystack docs `_. +* if not using ``aldryn_search``, you can define your own ``search_indexes.py`` by skipping ``aldryn_search`` installation and writing + your index for blog posts by following haystack documentation. To enable taggit filtering support in the admin install djangocms-blog with: diff --git a/requirements-test.txt b/requirements-test.txt index 15e0649c..ea5357b7 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -7,7 +7,6 @@ invoke tox>=2.0 wheel pysolr -aldryn-search django-taggit-helpers django-app-helper>=2.0.0a2 sphinx-autobuild diff --git a/tests/test_indexing.py b/tests/test_indexing.py index 5394aace..e32b33ef 100644 --- a/tests/test_indexing.py +++ b/tests/test_indexing.py @@ -1,4 +1,7 @@ +from unittest import skipIf + from cms.api import add_plugin +from django.test import override_settings from haystack.constants import DEFAULT_ALIAS from haystack.query import SearchQuerySet @@ -6,13 +9,19 @@ from .base import BaseTest +try: + import aldryn_search +except ImportError: + aldryn_search = None + class BlogIndexingTests(BaseTest): - sample_text = "First post first line This is the description keyword1 " "keyword2 category 1 a tag test body" + sample_text = "First post first line This is the description keyword1 keyword2 category 1 a tag test body" def setUp(self): self.get_pages() + @skipIf(aldryn_search is None, "aldryn-search not installed") def test_blog_post_is_indexed_using_prepare(self): """This tests the indexing path way used by update_index mgmt command""" post = self._get_post(self._post_data[0]["en"]) @@ -31,6 +40,28 @@ def test_blog_post_is_indexed_using_prepare(self): self.assertEqual(post.get_absolute_url(), indexed["url"]) self.assertEqual(post.date_published, indexed["pub_date"]) + @skipIf(aldryn_search is None, "aldryn-search not installed") + @override_settings(BLOG_USE_PLACEHOLDER=False) + def test_blog_post_is_indexed_using_prepare_no_placeholder(self): + """This tests the indexing path way used by update_index mgmt command when not using placeholder content""" + post = self._get_post(self._post_data[0]["en"]) + post = self._get_post(self._post_data[0]["it"], post, "it") + post.tags.add("a tag") + add_plugin(post.content, "TextPlugin", language="en", body="test body") + post.post_text = "non placeholder content" + + index = self.get_post_index() + index.index_queryset(DEFAULT_ALIAS) # initialises index._backend_alias + indexed = index.prepare(post) + + self.assertEqual(post.get_title(), indexed["title"]) + self.assertEqual(post.get_description(), indexed["description"]) + self.assertEqual(post.get_tags(), indexed["tags"]) + self.assertNotEqual(self.sample_text, indexed["text"]) + self.assertTrue(post.post_text in indexed["text"]) + self.assertEqual(post.get_absolute_url(), indexed["url"]) + self.assertEqual(post.date_published, indexed["pub_date"]) + def test_searchqueryset(self): posts = self.get_posts() all_results = SearchQuerySet().models(Post) diff --git a/tox.ini b/tox.ini index 742c4f57..0950ec97 100644 --- a/tox.ini +++ b/tox.ini @@ -8,8 +8,8 @@ envlist = pep8 pypi-description towncrier - py{3.8,3.7,3.6}-django{30}-cms{37} - py{3.8,3.7,3.6,3.5}-django{22}-cms{37} + py{3.8,3.7,3.6}-django{30}-cms{37,no-search-37} + py{3.8,3.7,3.6,3.5}-django{22}-cms{37,no-search-37} [testenv] commands = {env:COMMAND:python} cms_helper.py djangocms_blog test {posargs} @@ -18,6 +18,7 @@ deps = django22: django-mptt>=0.8 django22: django-filer>=1.5,<1.6 django22: django-appdata>=0.2.2 + django22: django-haystack django30: Django>=3.0,<3.1 django30: django-mptt>=0.9 django30: django-filer>=1.6 @@ -25,6 +26,8 @@ deps = django30: django-haystack==3.0b2 django30: https://github.com/yakky/djangocms-text-ckeditor/archive/master.zip cms37: https://github.com/divio/django-cms/archive/release/3.7.x.zip + cms37: aldryn-search + cms-no-search-37: https://github.com/divio/django-cms/archive/release/3.7.x.zip channels>2 https://github.com/nephila/django-knocker/archive/master.zip channels-redis