Initial commit
This commit is contained in:
175
env/lib/python3.10/site-packages/wagtail/search/models.py
vendored
Normal file
175
env/lib/python3.10/site-packages/wagtail/search/models.py
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
from django.apps import apps
|
||||
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db import connection, models
|
||||
from django.db.models.fields import TextField
|
||||
from django.db.models.fields.related import OneToOneField
|
||||
from django.db.models.functions import Cast
|
||||
from django.db.models.sql.where import WhereNode
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from .index import class_is_indexed
|
||||
from .utils import get_descendants_content_types_pks
|
||||
|
||||
|
||||
class TextIDGenericRelation(GenericRelation):
|
||||
auto_created = True
|
||||
|
||||
def get_content_type_lookup(self, alias, remote_alias):
|
||||
field = self.remote_field.model._meta.get_field(self.content_type_field_name)
|
||||
return field.get_lookup("in")(
|
||||
field.get_col(remote_alias), get_descendants_content_types_pks(self.model)
|
||||
)
|
||||
|
||||
def get_object_id_lookup(self, alias, remote_alias):
|
||||
from_field = self.remote_field.model._meta.get_field(self.object_id_field_name)
|
||||
to_field = self.model._meta.pk
|
||||
return from_field.get_lookup("exact")(
|
||||
from_field.get_col(remote_alias), Cast(to_field.get_col(alias), from_field)
|
||||
)
|
||||
|
||||
def get_extra_restriction(self, alias, remote_alias):
|
||||
cond = WhereNode()
|
||||
cond.add(self.get_content_type_lookup(alias, remote_alias), "AND")
|
||||
cond.add(self.get_object_id_lookup(alias, remote_alias), "AND")
|
||||
return cond
|
||||
|
||||
def resolve_related_fields(self):
|
||||
return []
|
||||
|
||||
|
||||
class BaseIndexEntry(models.Model):
|
||||
"""
|
||||
This is an abstract class that only contains fields common to all database vendors.
|
||||
It should be extended by the models specific for each backend.
|
||||
"""
|
||||
|
||||
content_type = models.ForeignKey(
|
||||
ContentType, on_delete=models.CASCADE, related_name="+"
|
||||
)
|
||||
# We do not use an IntegerField since primary keys are not always integers.
|
||||
object_id = models.CharField(max_length=50)
|
||||
content_object = GenericForeignKey()
|
||||
|
||||
# TODO: Add per-object boosting.
|
||||
# This field stores the "Title Normalisation Factor"
|
||||
# This factor is multiplied onto the rank of the title field.
|
||||
# This allows us to apply a boost to results with shorter titles
|
||||
# elevating more specific matches to the top.
|
||||
title_norm = models.FloatField(default=1.0)
|
||||
|
||||
wagtail_reference_index_ignore = True
|
||||
|
||||
class Meta:
|
||||
unique_together = ("content_type", "object_id")
|
||||
verbose_name = _("index entry")
|
||||
verbose_name_plural = _("index entries")
|
||||
abstract = True
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.content_type.name}: {self.content_object}"
|
||||
|
||||
@property
|
||||
def model(self):
|
||||
return self.content_type.model
|
||||
|
||||
@classmethod
|
||||
def add_generic_relations(cls):
|
||||
for model in apps.get_models():
|
||||
if class_is_indexed(model):
|
||||
TextIDGenericRelation(cls).contribute_to_class(model, "index_entries")
|
||||
|
||||
|
||||
# AbstractIndexEntry will be defined depending on which database system we're using.
|
||||
if connection.vendor == "postgresql":
|
||||
from django.contrib.postgres.indexes import GinIndex
|
||||
from django.contrib.postgres.search import SearchVectorField
|
||||
|
||||
class AbstractPostgresIndexEntry(BaseIndexEntry):
|
||||
"""
|
||||
This class is the specific IndexEntry model for PostgreSQL database systems.
|
||||
It inherits the fields defined in BaseIndexEntry, and adds PostgreSQL-specific
|
||||
fields (tsvectors), plus indexes for doing full-text search on those fields.
|
||||
"""
|
||||
|
||||
# TODO: Add per-object boosting.
|
||||
autocomplete = SearchVectorField()
|
||||
title = SearchVectorField()
|
||||
body = SearchVectorField()
|
||||
|
||||
class Meta(BaseIndexEntry.Meta):
|
||||
abstract = True
|
||||
# An additional computed GIN index on 'title || body' is created in a SQL migration
|
||||
# covers the default case of PostgresSearchQueryCompiler.get_index_vectors.
|
||||
indexes = [
|
||||
GinIndex(fields=["autocomplete"]),
|
||||
GinIndex(fields=["title"]),
|
||||
GinIndex(fields=["body"]),
|
||||
]
|
||||
|
||||
AbstractIndexEntry = AbstractPostgresIndexEntry
|
||||
|
||||
elif connection.vendor == "sqlite":
|
||||
from wagtail.search.backends.database.sqlite.utils import fts5_available
|
||||
|
||||
class AbstractSQLiteIndexEntry(BaseIndexEntry):
|
||||
"""
|
||||
This class is the specific IndexEntry model for SQLite database systems. The autocomplete, title, and body fields store additional
|
||||
"""
|
||||
|
||||
autocomplete = TextField(null=True)
|
||||
title = TextField(null=False)
|
||||
body = TextField(null=True)
|
||||
|
||||
class Meta(BaseIndexEntry.Meta):
|
||||
abstract = True
|
||||
|
||||
AbstractIndexEntry = AbstractSQLiteIndexEntry
|
||||
|
||||
if fts5_available():
|
||||
|
||||
class SQLiteFTSIndexEntry(models.Model):
|
||||
autocomplete = TextField(null=True)
|
||||
title = TextField(null=False)
|
||||
body = TextField(null=True)
|
||||
index_entry = OneToOneField(
|
||||
primary_key=True,
|
||||
to="wagtailsearch.indexentry",
|
||||
on_delete=models.CASCADE,
|
||||
db_column="rowid",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
db_table = "wagtailsearch_indexentry_fts"
|
||||
|
||||
elif connection.vendor == "mysql":
|
||||
|
||||
class AbstractMySQLIndexEntry(BaseIndexEntry):
|
||||
"""
|
||||
This class is the specific IndexEntry model for MySQL database systems.
|
||||
"""
|
||||
|
||||
autocomplete = TextField(null=True)
|
||||
title = TextField(null=False)
|
||||
body = TextField(null=True)
|
||||
|
||||
class Meta(BaseIndexEntry.Meta):
|
||||
abstract = True
|
||||
|
||||
AbstractIndexEntry = AbstractMySQLIndexEntry
|
||||
|
||||
else:
|
||||
AbstractIndexEntry = BaseIndexEntry
|
||||
|
||||
|
||||
class IndexEntry(AbstractIndexEntry):
|
||||
"""
|
||||
The IndexEntry model that will get created in the database.
|
||||
"""
|
||||
|
||||
class Meta(AbstractIndexEntry.Meta):
|
||||
"""
|
||||
Contains everything in the AbstractIndexEntry Meta class, but makes this model concrete.
|
||||
"""
|
||||
|
||||
abstract = False
|
||||
Reference in New Issue
Block a user