diff options
| author | Étienne Loks <etienne.loks@iggdrasil.net> | 2026-03-17 17:59:37 +0100 |
|---|---|---|
| committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2026-03-18 11:15:14 +0100 |
| commit | d760e9f87fe040ab33dcdb942303d39fbf83a9c8 (patch) | |
| tree | 19f071c01963f362b955c04bcef67babf2e65ca3 /ishtar_common | |
| parent | 6ce08c7273f63fdc24f7d4f71c4f8f05d7638458 (diff) | |
| download | Ishtar-d760e9f87fe040ab33dcdb942303d39fbf83a9c8.tar.bz2 Ishtar-d760e9f87fe040ab33dcdb942303d39fbf83a9c8.zip | |
⚡️ cache search counts
Diffstat (limited to 'ishtar_common')
| -rw-r--r-- | ishtar_common/migrations/0273_searchcache.py | 31 | ||||
| -rw-r--r-- | ishtar_common/models.py | 14 | ||||
| -rw-r--r-- | ishtar_common/models_common.py | 6 | ||||
| -rw-r--r-- | ishtar_common/views_item.py | 38 |
4 files changed, 83 insertions, 6 deletions
diff --git a/ishtar_common/migrations/0273_searchcache.py b/ishtar_common/migrations/0273_searchcache.py new file mode 100644 index 000000000..00b2f1fb1 --- /dev/null +++ b/ishtar_common/migrations/0273_searchcache.py @@ -0,0 +1,31 @@ +# Generated by Django 4.2.19 on 2026-03-17 16:02 + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('ishtar_common', '0272_ishtarsiteprofile_statementcondition'), + ] + + operations = [ + migrations.CreateModel( + name='SearchCache', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('query', models.TextField(blank=True, default='', verbose_name='Query')), + ('count', models.IntegerField(verbose_name='Count')), + ('updated', models.DateTimeField(default=django.utils.timezone.now)), + ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')), + ('ishtar_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='ishtar_common.ishtaruser')), + ], + options={ + 'verbose_name': 'Cache - Search count', + 'verbose_name_plural': 'Cache - Search counts', + }, + ), + ] diff --git a/ishtar_common/models.py b/ishtar_common/models.py index b9c00e1cd..65dddc051 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -95,7 +95,6 @@ from ishtar_common.utils import ( task, generate_pdf_preview, revoke_old_task, - InlineClass ) from ishtar_common.utils_secretary import IshtarSecretaryRenderer from ishtar_common.views_item import get_item @@ -2183,6 +2182,19 @@ class Dashboard(object): return v +class SearchCache(models.Model): + content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) + query = models.TextField(_("Query"), default="", blank=True) + ishtar_user = models.ForeignKey("IshtarUser", blank=True, null=True, + on_delete=models.CASCADE) + count = models.IntegerField(_("Count")) + updated = models.DateTimeField(default=timezone.now) + + class Meta: + verbose_name = _("Cache - Search count") + verbose_name_plural = _("Cache - Search counts") + + EXPORT_FORMATS = [("", "---")] EXPORT_FORMATS_CONTENT_TYPE = { "xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", diff --git a/ishtar_common/models_common.py b/ishtar_common/models_common.py index c90ca7309..a2708945f 100644 --- a/ishtar_common/models_common.py +++ b/ishtar_common/models_common.py @@ -5145,6 +5145,12 @@ class IdentifierItem(models.Model): super().save(*args, **kwargs) self.regenerate_all_ids() + # search cache clean + SearchCache = apps.get_model("ishtar_common", "SearchCache") + SearchCache.objects.filter( + content_type=ContentType.objects.get_for_model(self.__class__) + ).delete() + def regenerate_all_ids(self, save=True): if getattr(self, "_prevent_loop", False): return {} diff --git a/ishtar_common/views_item.py b/ishtar_common/views_item.py index 82eb4c7a8..18e3f5576 100644 --- a/ishtar_common/views_item.py +++ b/ishtar_common/views_item.py @@ -2908,13 +2908,41 @@ def get_item( if col.startswith(k): count_values.append(v) break - try: - q = items.values(*count_values) - items_nb = q.count() or 0 - except ProgrammingError: - items_nb = 0 + + # count in cache + n = datetime.datetime.now() + + search_vector = request_items.get("search_vector", "").strip() + + # cache only for GUI search + cache_search = search_vector or "submited" in request_items + q_cached_count = None + if cache_search: + q_cached_count_attrs = { + "content_type": ContentType.objects.get_for_model(model), + "query": search_vector, + "updated__gt": timezone.now() - datetime.timedelta(hours=24) + } + if own: + q_cached_count_attrs["ishtar_user_id"] = ishtaruser.user_ptr_id + SearchCache = apps.get_model("ishtar_common", "SearchCache") + q_cached_count = SearchCache.objects.filter(**q_cached_count_attrs) + if cache_search and q_cached_count.exists(): + items_nb = q_cached_count.all()[0].count + else: + try: + q = items.values(*count_values) + items_nb = q.count() or 0 + except ProgrammingError: + items_nb = 0 + if cache_search: + q_cached_count_attrs.pop("updated__gt") + q_cached_count_attrs["count"] = items_nb + SearchCache.objects.create(**q_cached_count_attrs) + if count: return items_nb + # print(str(items.values("id").query)) if data_type == "json-stats": |
