From 90a62523d1055af15f1da40b2047dd667d6e023c Mon Sep 17 00:00:00 2001 From: Lucas Moeskops Date: Sat, 30 Apr 2016 19:40:06 +0200 Subject: [PATCH] Support for foreign related objects for Elasticsearch backend search. See pull request #2547. --- .../tests/search/migrations/0003_subobject.py | 22 ++++++++++++ wagtail/tests/search/models.py | 11 ++++++ wagtail/wagtailsearch/index.py | 3 ++ wagtail/wagtailsearch/tests/test_backends.py | 1 + .../tests/test_elasticsearch_backend.py | 36 ++++++++++++++++--- 5 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 wagtail/tests/search/migrations/0003_subobject.py diff --git a/wagtail/tests/search/migrations/0003_subobject.py b/wagtail/tests/search/migrations/0003_subobject.py new file mode 100644 index 000000000..a4b25b0fd --- /dev/null +++ b/wagtail/tests/search/migrations/0003_subobject.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('searchtests', '0002_anothersearchtestchild'), + ] + + operations = [ + migrations.CreateModel( + name='SearchTestSubObject', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('parent', models.ForeignKey(to='searchtests.SearchTest', related_name='subobjects', on_delete=models.deletion.CASCADE)), + ('name', models.CharField(max_length=255)), + ], + bases=(models.Model,), + ), + ] diff --git a/wagtail/tests/search/models.py b/wagtail/tests/search/models.py index 84c57c113..e40c0a9cc 100644 --- a/wagtail/tests/search/models.py +++ b/wagtail/tests/search/models.py @@ -19,6 +19,9 @@ class SearchTest(index.Indexed, models.Model): index.SearchField('name', partial_match=True), index.FilterField('slug'), ]), + index.RelatedFields('subobjects', [ + index.SearchField('name', partial_match=True), + ]), index.SearchField('content'), index.SearchField('callable_indexed_field'), index.FilterField('title'), @@ -79,3 +82,11 @@ class AnotherSearchTestChild(SearchTest): search_fields = SearchTest.search_fields + [ index.SearchField('subtitle', boost=10), ] + + +class SearchTestSubObject(models.Model): + parent = models.ForeignKey(SearchTest, related_name='subobjects') + name = models.CharField(max_length=255) + + def __str__(self): + return self.name diff --git a/wagtail/wagtailsearch/index.py b/wagtail/wagtailsearch/index.py index dc650f5cf..0a267e016 100644 --- a/wagtail/wagtailsearch/index.py +++ b/wagtail/wagtailsearch/index.py @@ -245,6 +245,9 @@ class RelatedFields(object): if isinstance(field, RelatedField): return getattr(obj, self.field_name) + if isinstance(field, ForeignObjectRel): + return getattr(obj, self.field_name) + def select_on_queryset(self, queryset): """ This method runs either prefetch_related or select_related on the queryset diff --git a/wagtail/wagtailsearch/tests/test_backends.py b/wagtail/wagtailsearch/tests/test_backends.py index 9c10ec010..81af5a8b3 100644 --- a/wagtail/wagtailsearch/tests/test_backends.py +++ b/wagtail/wagtailsearch/tests/test_backends.py @@ -55,6 +55,7 @@ class BackendTests(WagtailTestUtils): testa = models.SearchTest() testa.title = "Hello World" testa.save() + testa.subobjects.create(name='A subobject') self.backend.add(testa) self.testa = testa diff --git a/wagtail/wagtailsearch/tests/test_elasticsearch_backend.py b/wagtail/wagtailsearch/tests/test_elasticsearch_backend.py index 9df975183..05713452d 100644 --- a/wagtail/wagtailsearch/tests/test_elasticsearch_backend.py +++ b/wagtail/wagtailsearch/tests/test_elasticsearch_backend.py @@ -90,6 +90,10 @@ class TestElasticsearchSearchBackend(BackendTests, TestCase): self.assertEqual(len(results), 1) self.assertEqual(results[0].id, obj.id) + def test_related_objects_search(self): + results = self.backend.search("A subobject", models.SearchTest) + self.assertEqual(set(results), {self.testa}) + def test_ascii_folding(self): # Reset the index self.reset_index() @@ -754,6 +758,7 @@ class TestElasticsearchMapping(TestCase): self.obj = models.SearchTest(title="Hello") self.obj.save() self.obj.tags.add("a tag") + self.obj.subobjects.create(name="A subobject") def test_get_document_type(self): self.assertEqual(self.es_mapping.get_document_type(), 'searchtests_searchtest') @@ -780,7 +785,13 @@ class TestElasticsearchMapping(TestCase): 'properties': { 'name': {'type': 'string', 'include_in_all': True, 'index_analyzer': 'edgengram_analyzer'}, 'slug_filter': {'index': 'not_analyzed', 'type': 'string', 'include_in_all': False}, - } + }, + }, + 'subobjects': { + 'type': 'nested', + 'properties': { + 'name': {'type': 'string', 'include_in_all': True, 'index_analyzer': 'edgengram_analyzer'}, + }, }, } } @@ -803,7 +814,7 @@ class TestElasticsearchMapping(TestCase): expected_result = { 'pk': str(self.obj.pk), 'content_type': 'searchtests_searchtest', - '_partials': ['Hello', 'a tag'], + '_partials': ['A subobject', 'Hello', 'a tag'], 'live_filter': False, 'published_date_filter': None, 'title': 'Hello', @@ -816,6 +827,11 @@ class TestElasticsearchMapping(TestCase): 'slug_filter': 'a-tag', } ], + 'subobjects': [ + { + 'name': 'A subobject' + } + ], } self.assertDictEqual(document, expected_result) @@ -836,6 +852,7 @@ class TestElasticsearchMappingInheritance(TestCase): self.obj = models.SearchTestChild(title="Hello", subtitle="World", page_id=1) self.obj.save() self.obj.tags.add("a tag") + self.obj.subobjects.create(name="A subobject") def test_get_document_type(self): self.assertEqual(self.es_mapping.get_document_type(), 'searchtests_searchtest_searchtests_searchtestchild') @@ -875,7 +892,13 @@ class TestElasticsearchMappingInheritance(TestCase): 'properties': { 'name': {'type': 'string', 'include_in_all': True, 'index_analyzer': 'edgengram_analyzer'}, 'slug_filter': {'index': 'not_analyzed', 'type': 'string', 'include_in_all': False}, - } + }, + }, + 'subobjects': { + 'type': 'nested', + 'properties': { + 'name': {'type': 'string', 'include_in_all': True, 'index_analyzer': 'edgengram_analyzer'}, + }, }, } } @@ -913,7 +936,7 @@ class TestElasticsearchMappingInheritance(TestCase): # Inherited 'pk': str(self.obj.pk), - '_partials': ['Hello', 'Root', 'World', 'a tag'], + '_partials': ['A subobject', 'Hello', 'Root', 'World', 'a tag'], 'live_filter': False, 'published_date_filter': None, 'title': 'Hello', @@ -926,6 +949,11 @@ class TestElasticsearchMappingInheritance(TestCase): 'slug_filter': 'a-tag', } ], + 'subobjects': [ + { + 'name': 'A subobject', + } + ], } self.assertDictEqual(document, expected_result)