summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/management/commands/relations_update_cache_tables.py83
-rw-r--r--ishtar_common/migrations/0215_ishtarsiteprofile_parent_relations_engine.py20
-rw-r--r--ishtar_common/models.py91
3 files changed, 194 insertions, 0 deletions
diff --git a/ishtar_common/management/commands/relations_update_cache_tables.py b/ishtar_common/management/commands/relations_update_cache_tables.py
new file mode 100644
index 000000000..ab7f134ff
--- /dev/null
+++ b/ishtar_common/management/commands/relations_update_cache_tables.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright (C) 2013-2018 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# See the file COPYING for details.
+
+import sys
+
+from django.core.management.base import BaseCommand
+
+from django.apps import apps
+
+
+APPS = ['ishtar_common', 'archaeological_operations',
+ 'archaeological_context_records', 'archaeological_finds',
+ 'archaeological_warehouse']
+
+
+class Command(BaseCommand):
+ args = ''
+ help = 'Regenerate geo, cached labels and search vectors'
+
+ def add_arguments(self, parser):
+ parser.add_argument('app_name', nargs='?', default=None,
+ choices=APPS)
+ parser.add_argument('model_name', nargs='?', default=None)
+ parser.add_argument(
+ '--quiet', dest='quiet', action='store_true',
+ help='Quiet output')
+
+ def handle(self, *args, **options):
+ quiet = options['quiet']
+ limit = options['app_name']
+ model_name = options['model_name']
+ if model_name:
+ model_name = model_name.lower()
+ for app in APPS:
+ if limit and app != limit:
+ continue
+ if not quiet:
+ print("* app: {}".format(app))
+ for model in apps.get_app_config(app).get_models():
+ if model_name and model.__name__.lower() != model_name:
+ continue
+ if model.__name__.startswith('Historical'):
+ continue
+ if not bool(
+ [k for k in dir(model)
+ if k.startswith('_generate_') or
+ k == "search_vector"]):
+ continue
+ msg = "-> processing {}: ".format(model._meta.verbose_name)
+ ln = model.objects.count()
+ for idx, obj_id in enumerate(model.objects.values('pk').all()):
+ obj = model.objects.get(pk=obj_id['pk'])
+ obj.skip_history_when_saving = True
+ obj._no_move = True
+ if hasattr(obj, "point_source") and obj.point_source in (
+ "M", "T"):
+ obj.point = None
+ obj.point_2d = None
+ obj.x = None
+ obj.y = None
+ cmsg = "\r{} {}/{}".format(msg, idx + 1, ln)
+ if not quiet:
+ sys.stdout.write(cmsg)
+ sys.stdout.flush()
+ obj.save()
+ if not quiet:
+ sys.stdout.write("\n")
diff --git a/ishtar_common/migrations/0215_ishtarsiteprofile_parent_relations_engine.py b/ishtar_common/migrations/0215_ishtarsiteprofile_parent_relations_engine.py
new file mode 100644
index 000000000..acf410837
--- /dev/null
+++ b/ishtar_common/migrations/0215_ishtarsiteprofile_parent_relations_engine.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.28 on 2021-06-14 19:06
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('ishtar_common', '0214_auto_20210308_1628'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='ishtarsiteprofile',
+ name='parent_relations_engine',
+ field=models.CharField(choices=[('V', 'SQL views'), ('T', 'Cache tables')], default='V', help_text='If you experience performance problems with complex relations (for instance: complex statigraphic relations), set it to "Cache tables" in order to use static cache tables. Do not forget to update theses table with the "relations_update_cache_tables" manage.py command.', max_length=1, verbose_name='Parent relations engine'),
+ ),
+ ]
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index 94e02aafe..fdeba5f26 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -62,6 +62,7 @@ from django.core.exceptions import (
from django.core.files.base import ContentFile
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.urlresolvers import reverse
+from django.db import connection
from django.db.models import Q, Max, Count
from django.db.models.signals import post_save, post_delete, m2m_changed
from django.db.utils import DatabaseError
@@ -76,6 +77,8 @@ from ishtar_common.utils import (
get_current_profile,
duplicate_item,
get_image_path,
+ serialize_args_for_tasks,
+ task,
)
from ishtar_common.utils_secretary import IshtarSecretaryRenderer
@@ -825,6 +828,80 @@ def post_delete_record_relation(sender, instance, **kwargs):
q.delete()
+@task()
+def relation_view_update(sender, kwargs):
+ if isinstance(sender, (tuple, list)):
+ sender = apps.get_model(*sender)
+ sender._update(kwargs["item_id"])
+
+
+class RelationsViews(models.Model):
+ CREATE_SQL = "" # SQL view creation
+ DELETE_SQL = "" # SQL view deletion
+ CREATE_TABLE_SQL = "" # SQL table creation
+
+ class Meta:
+ managed = False
+ abstract = True
+
+ @classmethod
+ def _update(cls, item_id):
+ raise NotImplemented()
+
+ @classmethod
+ def update(cls, item_id):
+ profile = get_current_profile()
+ if profile.parent_relations_engine == "V":
+ return
+ if not settings.USE_BACKGROUND_TASK:
+ return relation_view_update(cls, {"item_id": item_id})
+ else:
+ sender, kwargs = serialize_args_for_tasks(
+ cls, None, {"item_id": item_id}
+ )
+ return relation_view_update.delay(sender, kwargs)
+
+ @classmethod
+ def create_table(cls):
+ raise NotImplemented()
+
+ @classmethod
+ def check_engine(cls):
+ """
+ Check view or table properly created with settings on the profile
+ :return: True if table or view updated
+ """
+ assert cls.CREATE_SQL
+ assert cls.DELETE_SQL
+ assert cls.CREATE_TABLE_SQL
+ profile = get_current_profile(force=True)
+ table_type = ''
+ with connection.cursor() as cursor:
+ q = "select table_type from information_schema.tables WHERE " \
+ "table_name=%s;"
+ cursor.execute(q, [cls._meta.db_table])
+ q = cursor.fetchall()
+ if q:
+ table_type = q[0][0]
+
+ if profile.parent_relations_engine == "V":
+ if table_type == 'VIEW':
+ return
+ elif 'TABLE' in table_type:
+ q = "DROP TABLE %s"
+ cursor.execute(q, [cls._meta.db_table])
+ cursor.execute(cls.CREATE_SQL)
+ return True
+
+ if profile.parent_relations_engine == "T":
+ if 'TABLE' in table_type:
+ return
+ elif table_type == 'VIEW':
+ cursor.execute(cls.DELETE_SQL)
+ cursor.execute(cls.CREATE_TABLE_SQL)
+ return True
+
+
class SearchQuery(models.Model):
label = models.TextField(_("Label"), blank=True, default="")
query = models.TextField(_("Query"), blank=True, default="")
@@ -918,6 +995,20 @@ class IshtarSiteProfile(models.Model, Cached):
_("Container - calculate weight only when all find has a weight"),
default=False,
)
+ parent_relations_engine = models.CharField(
+ _("Parent relations engine"),
+ choices=(
+ ("V", _("SQL views")),
+ ("T", _("Cache tables")),
+ ),
+ default="V",
+ max_length=1,
+ help_text=_("If you experience performance problems with complex relations "
+ "(for instance: complex statigraphic relations), set it to "
+ "\"Cache tables\" in order to use static cache tables. Do not "
+ "forget to update theses table with the "
+ "\"relations_update_cache_tables\" manage.py command.")
+ )
config = models.CharField(
_("Alternate configuration"),
max_length=200,