def _create_model_filter(self, models, backend): """Creates a filter for the given model/queryset list.""" from django.contrib.contenttypes.models import ContentType from ieltsapp.models import has_int_pk filters = Q() for model in models: filter = Q() # Process querysets. if isinstance(model, QuerySet): sub_queryset = model model = model.model queryset = sub_queryset.values_list("pk", flat=True) if has_int_pk(model): filter &= Q(object_id_int__in=queryset, ) else: queryset = queryset.annotate(watson_pk_str=RawSQL( backend.do_string_cast( connections[queryset.db], model._meta.pk.db_column or model._meta.pk.attname, ), ()), ).values_list("watson_pk_str", flat=True) filter &= Q(object_id__in=queryset, ) # Add the model to the filter. content_type = ContentType.objects.get_for_model(model) filter &= Q(content_type=content_type, ) # Combine with the other filters. filters |= filter return filters
def do_filter(self, engine_slug, queryset, search_text): """Performs the full text filter.""" model = queryset.model content_type = ContentType.objects.get_for_model(model) connection = connections[queryset.db] pk = model._meta.pk if has_int_pk(model): ref_name = "object_id_int" ref_name_typecast = "" else: ref_name = "object_id" # Cast to text to make join work with uuid columns ref_name_typecast = "::text" return queryset.extra( tables=("watson_searchentry",), where=( "watson_searchentry.engine_slug = %s", "watson_searchentry.search_tsv @@ to_tsquery('{search_config}', %s)".format( search_config=self.search_config ), "watson_searchentry.{ref_name} = {table_name}.{pk_name}{ref_name_typecast}".format( ref_name=ref_name, table_name=connection.ops.quote_name(model._meta.db_table), pk_name=connection.ops.quote_name(pk.db_column or pk.attname), ref_name_typecast=ref_name_typecast ), "watson_searchentry.content_type_id = %s" ), params=(engine_slug, self.escape_postgres_query(search_text), content_type.id), )
def do_filter(self, engine_slug, queryset, search_text): """Performs the full text filter.""" model = queryset.model content_type = ContentType.objects.get_for_model(model) connection = connections[queryset.db] pk = model._meta.pk if has_int_pk(model): ref_name = "object_id_int" else: ref_name = "object_id" return queryset.extra( tables=("watson_searchentry",), where=( "watson_searchentry.engine_slug = %s", "MATCH (watson_searchentry.title, watson_searchentry.description, watson_searchentry.content) " "AGAINST (%s IN BOOLEAN MODE)", "watson_searchentry.{ref_name} = {table_name}.{pk_name}".format( ref_name=ref_name, table_name=connection.ops.quote_name(model._meta.db_table), pk_name=connection.ops.quote_name(pk.db_column or pk.attname), ), "watson_searchentry.content_type_id = %s", ), params=(engine_slug, self._format_query(search_text), content_type.id), )
def do_filter(self, engine_slug, queryset, search_text): """Filters the given queryset according the the search logic for this backend.""" model = queryset.model connection = connections[queryset.db] 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 = [""" ({db_table}.{engine_slug} = %s) """, """ ({db_table}.{content_type_id} = %s) """] word_kwargs = { "db_table": db_table, "model_db_table": model_db_table, "engine_slug": connection.ops.quote_name("engine_slug"), "title": connection.ops.quote_name("title"), "description": connection.ops.quote_name("description"), "content": connection.ops.quote_name("content"), "content_type_id": connection.ops.quote_name("content_type_id"), "object_id": connection.ops.quote_name("object_id"), "object_id_int": connection.ops.quote_name("object_id_int"), "id": id, "iregex_operator": connection.operators["iregex"], } 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.append( """ ({db_table}.{title} {iregex_operator} OR {db_table}.{description} {iregex_operator} OR {db_table}.{content} {iregex_operator}) """ ) word_args.extend((regex, regex, regex)) # Compile the query. full_word_query = " AND ".join(word_query).format(**word_kwargs) return queryset.extra( tables=(db_table,), where=(full_word_query,), params=word_args, )
def _get_entries_for_obj(self, obj): """Returns a queryset of entries associate with the given obj.""" from django.contrib.contenttypes.models import ContentType from ieltsapp.models import SearchEntry, has_int_pk, get_str_pk model = obj.__class__ content_type = ContentType.objects.get_for_model(model) # Get the basic list of search entries. search_entries = SearchEntry.objects.filter( content_type=content_type, engine_slug=self._engine_slug, ) object_id = get_str_pk(obj, connections[search_entries.db]) if has_int_pk(model): # Do a fast indexed lookup. object_id_int = int(obj.pk) search_entries = search_entries.filter( object_id_int=object_id_int, ) else: # Alas, have to do a slow unindexed lookup. object_id_int = None search_entries = search_entries.filter(object_id=object_id, ) return object_id_int, search_entries