diff options
-rw-r--r-- | archaeological_context_records/models.py | 34 | ||||
-rw-r--r-- | archaeological_operations/models.py | 2 | ||||
-rw-r--r-- | archaeological_warehouse/models.py | 133 | ||||
-rw-r--r-- | ishtar_common/management/commands/ishtar_maintenance.py | 39 | ||||
-rw-r--r-- | ishtar_common/models_common.py | 5 | ||||
-rw-r--r-- | ishtar_common/utils.py | 6 |
6 files changed, 121 insertions, 98 deletions
diff --git a/archaeological_context_records/models.py b/archaeological_context_records/models.py index a14605a5f..0c63ed8e9 100644 --- a/archaeological_context_records/models.py +++ b/archaeological_context_records/models.py @@ -389,7 +389,7 @@ class GeographicSubTownItem(GeoItem): def post_save_geo(self, save=True): # manage geodata towns - if getattr(self, "_post_save_geo_ok", False): + if getattr(self, "_post_save_geo_ok", False) or not self.pk: # prevent infinite loop - should not happen, but... return self._post_save_geo_ok = True @@ -414,15 +414,31 @@ class GeographicSubTownItem(GeoItem): self.main_geodata = None modified = True + current_model = self.__class__ + main_item_is_set = current_model.objects.filter( + id=self.pk, + main_geodata__source_content_type__app_label=current_model._meta.app_label, + main_geodata__source_content_type__model=current_model._meta.model_name, + ).count() # main geo is set for the current model + for upper_attr in self.UPPER_GEO: - upper = getattr(self, upper_attr, None) - if upper and upper.main_geodata and \ - upper.main_geodata_id not in self.geodata.values_list( - "id", flat=True): - modified = True - self.geodata.add(upper.main_geodata) - if not self.main_geodata: - self.main_geodata = upper.main_geodata + q_dict = {"id": self.pk, f"{upper_attr}__main_geodata_id__isnull": False} + q = current_model.objects.filter(**q_dict) + if q.count(): + upper = None + main_geodata_id = q.values_list(f"{upper_attr}__main_geodata_id", flat=True)[0] + if main_geodata_id not in self.geodata.values_list("id", flat=True): + upper = getattr(self, upper_attr, None) + modified = True + self.geodata.add(upper.main_geodata) + + if not main_item_is_set: + if self.main_geodata_id != main_geodata_id: + if not upper: + upper = getattr(self, upper_attr, None) + modified = True + self.main_geodata = upper.main_geodata + main_item_is_set = True if modified and save: if settings.USE_BACKGROUND_TASK and hasattr(self, "no_post_process"): diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py index 6e6bfa53c..8fbba74be 100644 --- a/archaeological_operations/models.py +++ b/archaeological_operations/models.py @@ -271,6 +271,8 @@ class GeographicTownItem(GeoItem): pass if changed and save: + self.no_post_process() + self.save() post_save_geo(self.__class__, instance=self, created=False, update_fields=False, raw=False, using="default") return changed diff --git a/archaeological_warehouse/models.py b/archaeological_warehouse/models.py index 826f4444f..5df824d8f 100644 --- a/archaeological_warehouse/models.py +++ b/archaeological_warehouse/models.py @@ -22,7 +22,6 @@ import datetime import logging import uuid -from django.conf import settings from django.contrib.gis.db import models from django.contrib.postgres.indexes import GinIndex from django.core.exceptions import ObjectDoesNotExist @@ -272,6 +271,51 @@ post_delete.connect(post_save_cache, sender=WarehouseType) NO_DIVISION_ERROR = _("The division number {} has not been set for the warehouse {}.") +def warehouse_post_save_geo(item, q_check_town, save=True): + # manage geodata towns + if getattr(item, "_post_save_geo_ok", False): + # prevent infinite loop - should not happen, but... + return + item._post_save_geo_ok = True + if not q_check_town.count(): + town_id = None + q_geotown = GeoVectorData.objects.filter(pk=None) + else: + town_id = q_check_town.values_list("precise_town_id", flat=True)[0] + q_geotown = GeoVectorData.objects.filter( + source_content_type__model="town", + source_content_type__app_label="ishtar_common", + source_id=town_id, + multi_polygon__isnull=False) + q_geodata_town = item.geodata.filter( + source_content_type__model="town", + source_content_type__app_label="ishtar_common", + ) + changed = False + if not q_geotown.count(): + # no simple town - clean + for geo in q_geodata_town.all(): + item.geodata.remove(geo) + if item.main_geodata == geo: + item.main_geodata = None + changed = True + else: + for geo in q_geodata_town.exclude(source_id=town_id).all(): + item.geodata.remove(geo) + if item.main_geodata == geo: + item.main_geodata = None + changed = True + if not q_geodata_town.filter(source_id=town_id).count(): + item.geodata.add(q_geotown.all()[0]) + changed = True + + if changed and save: + item.skip_history_when_saving = True + item._no_move = True + item.save() + return changed + + class Warehouse( Address, DocumentItem, @@ -427,47 +471,8 @@ class Warehouse( return self.name def post_save_geo(self, save=True): - # manage geodata towns - if getattr(self, "_post_save_geo_ok", False): - # prevent infinite loop - should not happen, but... - return - self._post_save_geo_ok = True - if not self.precise_town: - q_geotown = GeoVectorData.objects.filter(pk=None) - else: - q_geotown = GeoVectorData.objects.filter( - source_content_type__model="town", - source_content_type__app_label="ishtar_common", - source_id=self.precise_town.pk, - multi_polygon__isnull=False) - q_geodata_town = self.geodata.filter( - source_content_type__model="town", - source_content_type__app_label="ishtar_common", - ) - changed = False - if not q_geotown.count(): - # no simple town - clean - for geo in q_geodata_town.all(): - self.geodata.remove(geo) - if self.main_geodata == geo: - self.main_geodata = None - changed = True - else: - current_geo_town = q_geotown.all()[0] - for geo in q_geodata_town.exclude(pk=current_geo_town.pk).all(): - self.geodata.remove(geo) - if self.main_geodata == geo: - self.main_geodata = None - changed = True - if not q_geodata_town.filter(pk=current_geo_town.pk).count(): - self.geodata.add(current_geo_town) - changed = True - - if changed and save: - self.skip_history_when_saving = True - self._no_move = True - self.save() - return changed + q_check_town = Warehouse.objects.filter(pk=self.pk, precise_town_id__isnull=False) + return warehouse_post_save_geo(self, q_check_town, save=save) def get_container_type_by_place(self, place: int): """ @@ -1227,48 +1232,8 @@ class Container( return self.cached_label or "" def post_save_geo(self, save=True): - # manage geodata towns - if getattr(self, "_post_save_geo_ok", False): - # prevent infinite loop - should not happen, but... - return - self._post_save_geo_ok = True - - if not self.location.precise_town: - town_id = None - q_geotown = GeoVectorData.objects.filter(pk=None) - else: - town_id = self.location.precise_town_id - q_geotown = GeoVectorData.objects.filter( - source_content_type__model="town", - source_content_type__app_label="ishtar_common", - source_id=self.location.precise_town_id, - multi_polygon__isnull=False) - q_geodata_town = self.geodata.filter( - source_content_type__model="town", - source_content_type__app_label="ishtar_common", - ) - changed = False - if not q_geotown.count(): - for geo in q_geodata_town.all(): - self.geodata.remove(geo) - if self.main_geodata == geo: - self.main_geodata = None - changed = True - else: - for geo in q_geodata_town.exclude(source_id=town_id).all(): - self.geodata.remove(geo) - if self.main_geodata == geo: - self.main_geodata = None - changed = True - if not q_geodata_town.filter(source_id=town_id).count(): - self.geodata.add(q_geotown.all()[0]) - changed = True - - if changed and save: - self.skip_history_when_saving = True - self._no_move = True - self.save() - return changed + q_check_town = Warehouse.objects.filter(pk=self.location_id, precise_town_id__isnull=False) + return warehouse_post_save_geo(self, q_check_town, save=save) @property def start_division_number(self): diff --git a/ishtar_common/management/commands/ishtar_maintenance.py b/ishtar_common/management/commands/ishtar_maintenance.py index e4943ea8d..106575570 100644 --- a/ishtar_common/management/commands/ishtar_maintenance.py +++ b/ishtar_common/management/commands/ishtar_maintenance.py @@ -18,7 +18,7 @@ from django.core.management.base import BaseCommand, CommandError from django.template.defaultfilters import slugify from ishtar_common import models_common -from ishtar_common.utils import create_default_areas +from ishtar_common.utils import create_default_areas, BColors APPS = ( "ishtar_common", @@ -184,6 +184,33 @@ def _end_task(changed_nb, msg, quiet, store_results, log, log_name, csv_cols): sys.stdout.write(f"log: {path} written.\n") +def task_fix_geographic_items(options): + quiet = options.get("quiet", False) + filtr = options.get("filter", "") + model_filter = options.get('model', "").lower() + for model in apps.get_models(): + if not issubclass(model, models_common.GeographicItem) or not hasattr(model, "post_save_geo"): + continue + if model_filter and model_filter not in (model.__name__.lower(), model._meta.model_name.lower()): + continue + q = model.objects.exclude( + main_geodata__source_content_type__app_label=model._meta.app_label, + main_geodata__source_content_type__model=model._meta.model_name, + ) # main geo is set for the current model -> do not change + if filtr: + q = q.filter(**filtr) + nb = q.count() + total = 0 + for idx, item in enumerate(q.all()): + if not quiet: + msg = BColors.format("OKBLUE", f"\r→ {model.__name__}: {idx + 1}/{nb}" + " " * 20) + sys.stdout.write(msg) + total += 1 if item.post_save_geo() else 0 + if not quiet: + msg = BColors.format("OKGREEN", f"\n* {total} geographic(s) item(s) fixed for {model.__name__}\n") + sys.stdout.write(msg) + + def task_main_image(options): quiet = options.get("quiet", False) filtr = options.get("filter", "") @@ -300,6 +327,10 @@ TASKS = { "help": "create default areas from department and states", "action": task_default_areas, }, + "fix_geographic_items": { + "help": "check and fix geographic association and main geographic iem", + "action": task_fix_geographic_items, + }, "fix_main_image": { "help": "for items with images and no main image, put the first one created as a main image", "action": task_main_image, @@ -393,11 +424,13 @@ class Command(BaseCommand): quiet = options["quiet"] if not quiet: - sys.stdout.write(f"[{get_time()}] Processing task {options['task']}\n") + msg = BColors.format("HEADER", f"[{get_time()}] Processing task {options['task']}\n") + sys.stdout.write(msg) errors = TASKS[options["task"]]["action"](options) if not errors: if not quiet: - sys.stdout.write(f"\n[{get_time()}] Task {options['task']} finished\n") + msg = BColors.format("HEADER", f"[{get_time()}] Task {options['task']} finished\n") + sys.stdout.write(msg) if options["test"]: return sys.exit() diff --git a/ishtar_common/models_common.py b/ishtar_common/models_common.py index 9c081a022..ddf5d46d5 100644 --- a/ishtar_common/models_common.py +++ b/ishtar_common/models_common.py @@ -3302,9 +3302,10 @@ class MainItem(ShortMenuItem, SerializeItem, SheetItem): self._cached_label_checked = False cached_label_changed(self.__class__, instance=self, created=False) - def post_save_geo(self): + def post_save_geo(self, save=True): + if getattr(self, "_post_saved_geo", False): + return self.no_post_process() - self._post_saved_geo = False post_save_geo(self.__class__, instance=self, created=False) return False diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py index dd21bec06..f734a9b2d 100644 --- a/ishtar_common/utils.py +++ b/ishtar_common/utils.py @@ -151,6 +151,12 @@ class BColors: BOLD = "\033[1m" UNDERLINE = "\033[4m" + @classmethod + def format(cls, color, value): + if not hasattr(cls, color): + return value + return f"{getattr(cls, color)}{value}{cls.ENDC}" + class Round(models.Func): function = "ROUND" |