2011-08-20 17:08:00 +00:00
|
|
|
"""Models used by django-watson."""
|
|
|
|
|
|
2013-05-02 14:50:16 +00:00
|
|
|
from __future__ import unicode_literals
|
|
|
|
|
|
2017-12-06 16:51:57 +00:00
|
|
|
import uuid
|
|
|
|
|
|
2011-08-20 17:08:00 +00:00
|
|
|
from django.db import models
|
2022-01-08 03:20:03 +00:00
|
|
|
from django.db.models.fields.related import RelatedField
|
2011-08-20 17:08:00 +00:00
|
|
|
from django.contrib.contenttypes.models import ContentType
|
2020-03-29 10:17:35 +00:00
|
|
|
from django.utils.encoding import force_str
|
2015-10-12 11:01:12 +00:00
|
|
|
from django.utils.functional import cached_property
|
|
|
|
|
|
2015-02-17 09:59:53 +00:00
|
|
|
try:
|
|
|
|
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
|
|
|
|
except ImportError:
|
|
|
|
|
from django.contrib.contenttypes.generic import GenericForeignKey
|
2011-08-20 17:08:00 +00:00
|
|
|
|
2016-11-07 20:02:12 +00:00
|
|
|
|
2018-02-20 11:01:46 +00:00
|
|
|
INTEGER_FIELDS = (models.IntegerField, models.AutoField,)
|
|
|
|
|
BIG_INTEGER_FIELDS = (models.BigIntegerField,)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
BIG_INTEGER_FIELDS += (models.BigAutoField,)
|
|
|
|
|
except AttributeError: # Django < 2.0.
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2021-10-26 01:29:01 +00:00
|
|
|
def get_pk_output_field(model):
|
|
|
|
|
"""Gets an instance of the field type for the primary key of the given model, useful for database CAST."""
|
|
|
|
|
pk = model._meta.pk
|
2022-01-08 03:20:03 +00:00
|
|
|
if isinstance(pk, RelatedField):
|
|
|
|
|
return get_pk_output_field(pk.remote_field.model)
|
2021-10-26 01:29:01 +00:00
|
|
|
field_cls = type(pk)
|
|
|
|
|
field_kwargs = {}
|
|
|
|
|
if isinstance(pk, models.CharField):
|
|
|
|
|
# Some versions of Django produce invalid SQL for the CAST function (in some databases)
|
|
|
|
|
# if CharField does not have max_length passed.
|
|
|
|
|
# Therefore, it is necessary to copy over the max_length of the original field to avoid errors.
|
|
|
|
|
# See: https://code.djangoproject.com/ticket/28371
|
|
|
|
|
field_kwargs['max_length'] = pk.max_length
|
|
|
|
|
elif isinstance(pk, models.AutoField):
|
|
|
|
|
# Some versions of Django appear to also produce invalid SQL in MySQL
|
|
|
|
|
# when attempting to CAST with AutoField types.
|
|
|
|
|
# This covers for that by instead casting to the corresponding integer type.
|
|
|
|
|
if isinstance(pk, models.BigAutoField):
|
|
|
|
|
field_cls = models.BigIntegerField
|
|
|
|
|
else:
|
|
|
|
|
field_cls = models.IntegerField
|
|
|
|
|
return field_cls(**field_kwargs)
|
|
|
|
|
|
|
|
|
|
|
2011-08-20 17:08:00 +00:00
|
|
|
def has_int_pk(model):
|
|
|
|
|
"""Tests whether the given model has an integer primary key."""
|
2011-10-02 17:46:19 +00:00
|
|
|
pk = model._meta.pk
|
2011-08-20 17:08:00 +00:00
|
|
|
return (
|
2018-02-20 11:01:46 +00:00
|
|
|
isinstance(pk, INTEGER_FIELDS) and
|
|
|
|
|
not isinstance(pk, BIG_INTEGER_FIELDS)
|
|
|
|
|
) or (
|
|
|
|
|
isinstance(pk, models.ForeignKey) and has_int_pk(pk.remote_field.model)
|
2011-08-20 17:08:00 +00:00
|
|
|
)
|
2015-02-17 09:59:53 +00:00
|
|
|
|
|
|
|
|
|
2017-12-06 16:51:57 +00:00
|
|
|
def get_str_pk(obj, connection):
|
2020-03-29 10:17:35 +00:00
|
|
|
return obj.pk.hex if isinstance(obj.pk, uuid.UUID) and connection.vendor != "postgresql" else force_str(obj.pk)
|
2017-12-06 16:51:57 +00:00
|
|
|
|
|
|
|
|
|
2011-08-20 17:08:00 +00:00
|
|
|
META_CACHE_KEY = "_meta_cache"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SearchEntry(models.Model):
|
|
|
|
|
|
|
|
|
|
"""An entry in the search index."""
|
2015-02-17 09:59:53 +00:00
|
|
|
|
2011-08-23 16:12:35 +00:00
|
|
|
engine_slug = models.CharField(
|
2016-11-07 20:02:12 +00:00
|
|
|
max_length=200,
|
|
|
|
|
db_index=True,
|
|
|
|
|
default="default",
|
2011-08-23 16:12:35 +00:00
|
|
|
)
|
2015-02-17 09:59:53 +00:00
|
|
|
|
2011-08-20 17:08:00 +00:00
|
|
|
content_type = models.ForeignKey(
|
|
|
|
|
ContentType,
|
2017-07-22 11:43:29 +00:00
|
|
|
on_delete=models.CASCADE,
|
2011-08-20 17:08:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
object_id = models.TextField()
|
2015-02-17 09:59:53 +00:00
|
|
|
|
2011-08-20 17:08:00 +00:00
|
|
|
object_id_int = models.IntegerField(
|
2016-11-07 20:02:12 +00:00
|
|
|
blank=True,
|
|
|
|
|
null=True,
|
|
|
|
|
db_index=True,
|
2011-08-20 17:08:00 +00:00
|
|
|
)
|
2015-02-17 09:59:53 +00:00
|
|
|
|
|
|
|
|
object = GenericForeignKey()
|
|
|
|
|
|
2011-08-23 16:12:35 +00:00
|
|
|
title = models.CharField(
|
2016-11-07 20:02:12 +00:00
|
|
|
max_length=1000,
|
2011-08-23 16:12:35 +00:00
|
|
|
)
|
2015-02-17 09:59:53 +00:00
|
|
|
|
2011-08-23 16:12:35 +00:00
|
|
|
description = models.TextField(
|
2016-11-07 20:02:12 +00:00
|
|
|
blank=True,
|
2011-08-23 16:12:35 +00:00
|
|
|
)
|
2015-02-17 09:59:53 +00:00
|
|
|
|
2011-08-23 16:12:35 +00:00
|
|
|
content = models.TextField(
|
2016-11-07 20:02:12 +00:00
|
|
|
blank=True,
|
2011-08-23 16:12:35 +00:00
|
|
|
)
|
2015-02-17 09:59:53 +00:00
|
|
|
|
2011-08-23 16:12:35 +00:00
|
|
|
url = models.CharField(
|
2016-11-07 20:02:12 +00:00
|
|
|
max_length=1000,
|
|
|
|
|
blank=True,
|
2011-08-23 16:12:35 +00:00
|
|
|
)
|
2015-02-17 09:59:53 +00:00
|
|
|
|
2011-08-20 17:08:00 +00:00
|
|
|
meta_encoded = models.TextField()
|
2015-02-17 09:59:53 +00:00
|
|
|
|
2015-09-07 19:16:17 +00:00
|
|
|
def _deserialize_meta(self):
|
2015-12-02 10:39:36 +00:00
|
|
|
from watson.search import SearchEngine
|
2015-10-12 11:01:12 +00:00
|
|
|
engine = SearchEngine._created_engines[self.engine_slug]
|
2015-10-12 14:35:27 +00:00
|
|
|
model = ContentType.objects.get_for_id(self.content_type_id).model_class()
|
2015-10-12 11:01:12 +00:00
|
|
|
adapter = engine.get_adapter(model)
|
|
|
|
|
return adapter.deserialize_meta(self.meta_encoded)
|
2015-09-07 19:16:17 +00:00
|
|
|
|
2015-10-12 11:01:12 +00:00
|
|
|
@cached_property
|
2011-08-20 17:08:00 +00:00
|
|
|
def meta(self):
|
|
|
|
|
"""Returns the meta information stored with the search entry."""
|
|
|
|
|
# Attempt to use the cached value.
|
|
|
|
|
if hasattr(self, META_CACHE_KEY):
|
|
|
|
|
return getattr(self, META_CACHE_KEY)
|
|
|
|
|
# Decode the meta.
|
2015-09-07 19:16:17 +00:00
|
|
|
meta_value = self._deserialize_meta()
|
2011-08-20 17:08:00 +00:00
|
|
|
setattr(self, META_CACHE_KEY, meta_value)
|
|
|
|
|
return meta_value
|
2015-02-17 09:59:53 +00:00
|
|
|
|
2011-08-23 16:12:35 +00:00
|
|
|
def get_absolute_url(self):
|
|
|
|
|
"""Returns the URL of the referenced object."""
|
|
|
|
|
return self.url
|
2015-02-17 09:59:53 +00:00
|
|
|
|
2017-11-23 13:48:14 +00:00
|
|
|
def __str__(self):
|
|
|
|
|
"""Returns a string representation."""
|
2011-08-23 16:12:35 +00:00
|
|
|
return self.title
|
2015-02-17 09:59:53 +00:00
|
|
|
|
2011-08-23 16:12:35 +00:00
|
|
|
class Meta:
|
2013-05-02 14:50:16 +00:00
|
|
|
verbose_name_plural = "search entries"
|
2015-02-17 10:02:42 +00:00
|
|
|
app_label = 'watson'
|