瀏覽代碼

Add ability to disable search indexing for a model #9821

- Add tests for search disable capability
- Update index disable to use empty search_fields property
- Relates to #7570
Daniel Kirkham 2 年之前
父節點
當前提交
af57a3eb7e

+ 1 - 0
CHANGELOG.txt

@@ -18,6 +18,7 @@ Changelog
  * Messages added dynamically via JavaScript now have an icon to be consistent with those supplied in the page's HTML (Aman Pandey)
  * Switch lock/unlock side panel toggle to a switch, with more appropriate confirmation message status (Sage Abdullah)
  * Ensure that changed or cleared selection from choosers will dispatch a DOM `change` event (George Sakkis)
+ * Add the ability to disable model indexing by setting `search_fields = []` (Daniel Kirkham)
  * Fix: Ensure `label_format` on StructBlock gracefully handles missing variables (Aadi jindal)
  * Fix: Adopt a no-JavaScript and more accessible solution for the 'Reset to default' switch to Gravatar when editing user profile (Loveth Omokaro)
  * Fix: Ensure `Site.get_site_root_paths` works on cache backends that do not preserve Python objects (Jaap Roes)

+ 1 - 0
docs/releases/5.0.md

@@ -30,6 +30,7 @@ Support for adding custom validation logic to StreamField blocks has been formal
  * Messages added dynamically via JavaScript now have an icon to be consistent with those supplied in the page's HTML (Aman Pandey)
  * Switch lock/unlock side panel toggle to a switch, with more appropriate confirmation message status (Sage Abdullah)
  * Ensure that changed or cleared selection from choosers will dispatch a DOM `change` event (George Sakkis)
+ * Add the ability to [disable model indexing](wagtailsearch_disable_indexing) by setting `search_fields = []` (Daniel Kirkham)
 
 ### Bug fixes
 

+ 6 - 0
docs/topics/search/indexing.md

@@ -49,6 +49,12 @@ The search may not return any results while this command is running, so avoid ru
 The `update_index` command is also aliased as `wagtail_update_index`, for use when another installed package (such as [Haystack](https://haystacksearch.org/)) provides a conflicting `update_index` command. In this case, the other package's entry in `INSTALLED_APPS` should appear above `wagtail.search` so that its `update_index` command takes precedence over Wagtail's.
 ```
 
+(wagtailsearch_disable_indexing)=
+
+### Disabling model indexing
+
+Indexing of a model can be disabled completely by setting `search_fields = []` within the model. This will disable index updates by the signal handler and by the `update_index` management command.
+
 (wagtailsearch_indexing_fields)=
 
 ## Indexing extra fields

+ 3 - 0
wagtail/search/checks.py

@@ -10,6 +10,9 @@ def page_search_fields_check(app_configs, **kwargs):
     errors = []
 
     for cls in page_models:
+        # Don't check models where indexing has been explicitly disabled
+        if not cls.search_fields:
+            continue
         # Only checks an initial subset of fields as only need to check some are missing to show the warning
         if not all(field in cls.search_fields for field in Page.search_fields[:10]):
             errors.append(

+ 4 - 1
wagtail/search/index.py

@@ -128,7 +128,9 @@ def get_indexed_models():
     return [
         model
         for model in apps.get_models()
-        if issubclass(model, Indexed) and not model._meta.abstract
+        if issubclass(model, Indexed)
+        and not model._meta.abstract
+        and model.search_fields
     ]
 
 
@@ -137,6 +139,7 @@ def class_is_indexed(cls):
         issubclass(cls, Indexed)
         and issubclass(cls, models.Model)
         and not cls._meta.abstract
+        and cls.search_fields
     )
 
 

+ 5 - 0
wagtail/search/tests/test_backends.py

@@ -227,6 +227,11 @@ class BackendTests(WagtailTestUtils):
             [r.title for r in results], ["Learning Python", "Two Scoops of Django 1.11"]
         )
 
+    def test_search_all_unindexed(self):
+        # There should be no index entries for UnindexedBook
+        results = self.backend.search(MATCH_ALL, models.UnindexedBook)
+        self.assertEqual(len(results), 0)
+
     # AUTOCOMPLETE TESTS
 
     def test_autocomplete(self):

+ 23 - 0
wagtail/search/tests/test_index_functions.py

@@ -201,3 +201,26 @@ class TestSignalHandlers(WagtailTestUtils, TestCase):
         indexed_object = backend().add.call_args[0][0]
         self.assertEqual(indexed_object.title, "Updated test")
         self.assertEqual(indexed_object.publication_date, date(2017, 10, 18))
+
+
+@mock.patch("wagtail.search.tests.DummySearchBackend", create=True)
+@override_settings(
+    WAGTAILSEARCH_BACKENDS={
+        "default": {"BACKEND": "wagtail.search.tests.DummySearchBackend"}
+    }
+)
+class TestSignalHandlersSearchDisabled(TestCase, WagtailTestUtils):
+    def test_index_on_create_and_update(self, backend):
+        obj = models.UnindexedBook.objects.create(
+            title="Test", publication_date=date(2017, 10, 18), number_of_pages=100
+        )
+
+        self.assertEqual(backend().add.call_count, 0)
+        self.assertIsNone(backend().add.call_args)
+
+        backend().reset_mock()
+        obj.title = "Updated test"
+        obj.save()
+
+        self.assertEqual(backend().add.call_count, 0)
+        self.assertIsNone(backend().add.call_args)

+ 9 - 0
wagtail/search/tests/test_indexed_class.py

@@ -144,3 +144,12 @@ class TestSearchFields(TestCase):
                 if error.id == "wagtailsearch.W001"
             ]
             self.assertEqual([], errors)
+
+        # third check that we get no errors when disabling all model search
+        with patch_search_fields(EventPage, []):
+            errors = [
+                error
+                for error in checks.run_checks()
+                if error.id == "wagtailsearch.W001"
+            ]
+            self.assertEqual([], errors)

+ 36 - 0
wagtail/test/search/fixtures/search.json

@@ -244,6 +244,42 @@
       "number_of_pages": 622
     }
   },
+  {
+    "pk": 1,
+    "model": "searchtests.unindexedbook",
+    "fields": {
+      "title": "A Game of Thrones U",
+      "publication_date": "1996-08-01",
+      "number_of_pages": 694
+    }
+  },
+  {
+    "pk": 2,
+    "model": "searchtests.unindexedbook",
+    "fields": {
+      "title": "A Clash of Kings U",
+      "publication_date": "1998-01-01",
+      "number_of_pages": 768
+    }
+  },
+  {
+    "pk": 3,
+    "model": "searchtests.unindexedbook",
+    "fields": {
+      "title": "A Storm of Swords U",
+      "publication_date": "2000-01-01",
+      "number_of_pages": 973
+    }
+  },
+  {
+    "pk": 4,
+    "model": "searchtests.unindexedbook",
+    "fields": {
+      "title": "The Fellowship of the Ring U",
+      "publication_date": "1954-07-29",
+      "number_of_pages": 423
+    }
+  },
 
   {
     "pk": 1,

+ 43 - 0
wagtail/test/search/migrations/0002_bookunindexed.py

@@ -0,0 +1,43 @@
+# Generated by Django 4.1.4 on 2022-12-23 09:32
+
+from django.db import migrations, models
+import taggit.managers
+import wagtail.search.index
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("taggit", "0005_auto_20220424_2025"),
+        ("searchtests", "0001_initial"),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name="UnindexedBook",
+            fields=[
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                ("title", models.CharField(max_length=255)),
+                ("publication_date", models.DateField()),
+                ("number_of_pages", models.IntegerField()),
+                (
+                    "tags",
+                    taggit.managers.TaggableManager(
+                        help_text="A comma-separated list of tags.",
+                        through="taggit.TaggedItem",
+                        to="taggit.Tag",
+                        verbose_name="Tags",
+                    ),
+                ),
+            ],
+            bases=(wagtail.search.index.Indexed, models.Model),
+        ),
+    ]

+ 9 - 0
wagtail/test/search/models.py

@@ -123,3 +123,12 @@ class ProgrammingGuide(Book):
         index.SearchField("get_programming_language_display"),
         index.FilterField("programming_language"),
     ]
+
+
+class UnindexedBook(index.Indexed, models.Model):
+    title = models.CharField(max_length=255)
+    publication_date = models.DateField()
+    number_of_pages = models.IntegerField()
+    tags = TaggableManager()
+
+    search_fields = []