diff --git a/src/watson/backends.py b/src/watson/backends.py index 9259a15..1049924 100644 --- a/src/watson/backends.py +++ b/src/watson/backends.py @@ -59,11 +59,55 @@ class SearchBackend(object): def do_filter(self, engine_slug, queryset, search_text): """Filters the given queryset according the the search logic for this backend.""" word_query = Q(searchentry_set__engine_slug=engine_slug) + model = queryset.model + db_table = connection.ops.quote_name(SearchEntry._meta.db_table) + model_db_table = connection.ops.quote_name(model._meta.db_table) + pk = model._meta.pk + id = connection.ops.quote_name(pk.db_column or pk.attname) + # Add in basic filters. + word_query = [u""" + ({db_table}.{engine_slug} = %s) + """, """ + ({db_table}.{content_type_id} = %s) + """] + word_kwargs= { + u"db_table": db_table, + u"model_db_table": model_db_table, + u"engine_slug": connection.ops.quote_name(u"engine_slug"), + u"title": connection.ops.quote_name(u"title"), + u"description": connection.ops.quote_name(u"description"), + u"content": connection.ops.quote_name(u"content"), + u"content_type_id": connection.ops.quote_name(u"content_type_id"), + u"object_id": connection.ops.quote_name(u"object_id"), + u"object_id_int": connection.ops.quote_name(u"object_id_int"), + u"id": id, + } + word_args = [ + engine_slug, + ContentType.objects.get_for_model(model).id, + ] + # Add in join. + if has_int_pk(model): + word_query.append(""" + ({db_table}.{object_id_int} = {model_db_table}.{id}) + """) + else: + word_query.append(""" + ({db_table}.{object_id} = {model_db_table}.{id}) + """) + # Add in all words. for word in search_text.split(): regex = regex_from_word(word) - word_query &= (Q(searchentry_set__title__iregex=regex) | Q(searchentry_set__description__iregex=regex) | Q(searchentry_set__content__iregex=regex)) - return queryset.filter( - word_query + word_query.append(u""" + ({db_table}.{title} REGEXP '(?i)' || %s OR {db_table}.{description} REGEXP '(?i)' || %s OR {db_table}.{content} REGEXP '(?i)' || %s) + """) + word_args.extend((regex, regex, regex)) + # Compile the query. + full_word_query = u" AND ".join(word_query).format(**word_kwargs) + return queryset.extra( + tables = (db_table,), + where = (full_word_query,), + params = word_args, ) def do_filter_ranking(self, engine_slug, queryset, search_text): diff --git a/src/watson/registration.py b/src/watson/registration.py index 1c779b9..2ff23a2 100644 --- a/src/watson/registration.py +++ b/src/watson/registration.py @@ -345,18 +345,6 @@ class SearchEngine(object): # Perform the registration. adapter_obj = adapter_cls(model) self._registered_models[model] = adapter_obj - # Add in a generic relation, if not exists. - if not hasattr(model, "searchentry_set"): - if has_int_pk(model): - object_id_field = "object_id_int" - else: - object_id_field = "object_id" - generic_relation = generic.GenericRelation( - SearchEntry, - object_id_field = object_id_field, - ) - model.searchentry_set = generic_relation - generic_relation.contribute_to_class(model, "searchentry_set") # Connect to the signalling framework. post_save.connect(self._post_save_receiver, model) pre_delete.connect(self._pre_delete_receiver, model) diff --git a/src/watson/tests.py b/src/watson/tests.py index 691e57c..2675dd7 100644 --- a/src/watson/tests.py +++ b/src/watson/tests.py @@ -197,7 +197,8 @@ class InternalsTest(SearchTestBase): self.assertEqual(len(exact_search), 1) self.assertEqual(exact_search[0].title, "fooo") # Delete a model and make sure that the search results match. - self.test11.delete() + with watson.update_index(): + self.test11.delete() self.assertEqual(watson.search("fooo").count(), 0) def testSearchIndexUpdateAbandonedOnError(self):