diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2025-02-06 17:56:14 +0100 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2025-02-19 14:45:57 +0100 |
commit | 1d049ac1cac1aa74610e298f5d074527dabdbb5c (patch) | |
tree | 445d97245a46afef7ac79b7782318ed50aa46976 /ishtar_common | |
parent | 32b4271ea9e7540a7613429563fffde20e57690d (diff) | |
download | Ishtar-1d049ac1cac1aa74610e298f5d074527dabdbb5c.tar.bz2 Ishtar-1d049ac1cac1aa74610e298f5d074527dabdbb5c.zip |
✨ Town, area searches for person, organisations, archaeological files, context records, warehouses and containers (refs #6095)
Diffstat (limited to 'ishtar_common')
-rw-r--r-- | ishtar_common/forms_common.py | 9 | ||||
-rw-r--r-- | ishtar_common/models.py | 7 | ||||
-rw-r--r-- | ishtar_common/models_common.py | 10 | ||||
-rw-r--r-- | ishtar_common/views_item.py | 159 |
4 files changed, 130 insertions, 55 deletions
diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py index 187941bb6..1858c7246 100644 --- a/ishtar_common/forms_common.py +++ b/ishtar_common/forms_common.py @@ -836,10 +836,14 @@ class OrganizationSelect(CustomForm, TableSelect): name = forms.CharField(label=_("Name"), max_length=300) organization_type = forms.ChoiceField(label=_("Type"), choices=[]) precise_town_id = get_town_field() + area = forms.ChoiceField(label=_("Area"), choices=[]) museum_museofile_id = forms.CharField(label=_("Museofile ID"), required=False) + TYPES = [ + FieldType('area', models.Area), + ] def __init__(self, *args, **kwargs): - super(OrganizationSelect, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields["organization_type"].choices = models.OrganizationType.get_types() @@ -1038,9 +1042,12 @@ class PersonSelect(CustomForm, TableSelect): ), validators=[models.valid_id(models.Organization)], ) + precise_town_id = get_town_field(required=False) + area = forms.ChoiceField(label=_("Area"), choices=[]) TYPES = [ FieldType("person_types", models.PersonType), FieldType("title", models.TitleType), + FieldType('area', models.Area), ] diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 949120383..102e01f0a 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -2641,7 +2641,8 @@ organization_type_pks_lazy = lazy(OrganizationType.get_or_create_pks, str) class Organization(Address, Merge, OwnPerms, BaseGenderedType, ValueGetter, MainItem): - TABLE_COLS = ("name", "organization_type", "address", "town") #, "precise_town") + TABLE_COLS = ("name", "organization_type", "address", "town") + # , "precise_town") SLUG = "organization" SHOW_URL = "show-organization" DELETE_URL = "delete-organization" @@ -2677,6 +2678,7 @@ class Organization(Address, Merge, OwnPerms, BaseGenderedType, ValueGetter, Main "museum_museofile_id__iexact", ), } + ALT_NAMES.update(Address.ALT_NAMES) QA_EDIT = QuickAction( url="organization-qa-bulk-update", icon_class="fa fa-pencil", @@ -2934,7 +2936,7 @@ class Person(Address, Merge, OwnPerms, ValueGetter, MainItem): "title": SearchAltName( pgettext_lazy("key for text search", "title"), "title__label__iexact", related_name="title" - ), + ), "salutation": SearchAltName( pgettext_lazy("key for text search", "salutation"), "salutation__iexact" ), @@ -2957,6 +2959,7 @@ class Person(Address, Merge, OwnPerms, ValueGetter, MainItem): "profiles__profile_type__label__iexact", ), } + ALT_NAMES.update(Address.ALT_NAMES) QA_EDIT = QuickAction( url="person-qa-bulk-update", icon_class="fa fa-pencil", diff --git a/ishtar_common/models_common.py b/ishtar_common/models_common.py index 49c69e9e1..8fb49c5cc 100644 --- a/ishtar_common/models_common.py +++ b/ishtar_common/models_common.py @@ -3880,6 +3880,16 @@ class Address(BaseHistorizedItem): ) history = HistoricalRecords(inherit=True) SUB_ADDRESSES = [] + ALT_NAMES = { + "precise_town_id": SearchAltName( + pgettext_lazy("key for text search", "town"), + "precise_town_id" + ), + "area": SearchAltName( + pgettext_lazy("key for text search", "area"), + "precise_town__areas__label__iexact" + ), + } class Meta: abstract = True diff --git a/ishtar_common/views_item.py b/ishtar_common/views_item.py index cecc0318d..5d2c92899 100644 --- a/ishtar_common/views_item.py +++ b/ishtar_common/views_item.py @@ -1306,6 +1306,104 @@ def _manage_facet_search(model, dct, and_reqs): dct[k] = getattr(model, POST_PROCESS_REQUEST[k])(dct[k].replace('"', "")) +def _manage_hierarchic_precise_town(req, dct, and_reqs): + val = _clean_type_val(dct.pop(req)).strip('"') + if val.startswith('"') and val.endswith('"'): + val = val[1:-1] + vals = [v.replace('"', "") for v in val.split(";")] + town_ids = [] + Town = apps.get_model("ishtar_common", "Town") + for val in vals: + q = Town.objects.filter(cached_label__iexact=val).values_list( + "id", flat=True) + if not q.count(): + continue + town_id = q.all()[0] + town_ids.append(town_id) + for rel_query in ("parents__", "children__"): + for idx in range(HIERARCHIC_LEVELS): + k = rel_query * (idx + 1) + "pk" + q = Town.objects.filter( + **{k: town_id}).values_list("id", flat=True) + if not q.count(): + break + town_ids += list(q.all()) + main_req = Q(**{req + "__in": town_ids}) + and_reqs.append(main_req) + + +def _manage_hierarchic_precise_town_area(req, dct, and_reqs): + if req.endswith("pk"): + suffix = "pk" + elif req.endswith("label__iexact"): + suffix = "label__iexact" + else: + return + val = _clean_type_val(dct.pop(req)) + if val.startswith('"') and val.endswith('"'): + val = val[1:-1] + if val == "*": + req = req.replace("label__", "").replace("pk", "").replace( + "iexact", "" + ).replace("precise_town__areas", "precise_town_id") # * -> is attached to a town + req += "isnull" + reqs = Q(**{req: False}) + and_reqs.append(reqs) + return + elif "*" in val and "iexact" in suffix: + suffix = suffix.replace("iexact", "icontains") + req = req.replace("iexact", "icontains") + val = val.replace("*", "") + Town = apps.get_model("ishtar_common", "Town") + Area = apps.get_model("ishtar_common", "Area") + q_area = Area.objects.filter(**{suffix: val}) + q_towns = Town.objects.filter(areas__pk__in=q_area.values_list("pk", flat=True)) + req = req.replace("precise_town__areas__label__iexact", "precise_town_id__in") + val_towns = q_towns.values_list("pk", flat=True) + reqs = Q(**{req: val_towns}) + + for idx in range(HIERARCHIC_LEVELS): + suffix = "parent__" + suffix + q_area = Area.objects.filter(**{suffix: val}) + q_towns = Town.objects.filter(areas__pk__in=q_area.values_list("pk", flat=True)) + if q_towns.count(): + val_towns = q_towns.values_list("pk", flat=True) + q = Q(**{req: val_towns}) + reqs |= q + and_reqs.append(reqs) + + +def _manage_hierarchic_area(req, dct, and_reqs): + if req.endswith("pk"): + suffix = "pk" + elif req.endswith("label__iexact"): + suffix = "label__iexact" + else: + return + val = _clean_type_val(dct.pop(req)) + if val.startswith('"') and val.endswith('"'): + val = val[1:-1] + if val == "*": + req = req.replace("label__", "").replace("pk", "").replace("iexact", "") + req += "isnull" + reqs = Q(**{req: False}) + and_reqs.append(reqs) + return + elif "*" in val and "iexact" in suffix: + suffix = suffix.replace("iexact", "icontains") + req = req.replace("iexact", "icontains") + val = val.replace("*", "") + + reqs = Q(**{req: val}) + + for idx in range(HIERARCHIC_LEVELS): + req = req[: -(len(suffix))] + "parent__" + suffix + q = Q(**{req: val}) + reqs |= q + and_reqs.append(reqs) + # TODO: improve query with "IN ()"? + + def _manage_hierarchic_fields(model, dct, and_reqs): hierarchic_fields = HIERARCHIC_FIELDS[:] if hasattr(model, "hierarchic_fields"): @@ -1315,35 +1413,13 @@ def _manage_hierarchic_fields(model, dct, and_reqs): if type(reqs) not in (list, tuple): reqs = [reqs] for req in reqs: + if req.endswith( + "precise_town__areas__label__iexact" + ) or req.endswith("precise_town__areas__pk"): + _manage_hierarchic_precise_town_area(req, dct, and_reqs) + continue if req.endswith("areas__pk") or req.endswith("areas__label__iexact"): - if req.endswith("pk"): - suffix = "pk" - elif req.endswith("label__iexact"): - suffix = "label__iexact" - else: - continue - val = _clean_type_val(dct.pop(req)) - if val.startswith('"') and val.endswith('"'): - val = val[1:-1] - if val == "*": - req = req.replace("label__", "").replace("pk", "").replace("iexact", "") - req += "isnull" - reqs = Q(**{req: False}) - and_reqs.append(reqs) - continue - elif "*" in val and "iexact" in suffix: - suffix = suffix.replace("iexact", "icontains") - req = req.replace("iexact", "icontains") - val = val.replace("*", "") - - reqs = Q(**{req: val}) - - for idx in range(HIERARCHIC_LEVELS): - req = req[: -(len(suffix))] + "parent__" + suffix - q = Q(**{req: val}) - reqs |= q - and_reqs.append(reqs) - # TODO: improve query with "IN ()"? + _manage_hierarchic_area(req, dct, and_reqs) continue if req.endswith("wcontainer_id") or req.endswith("wcontainer_ref_id"): @@ -1371,32 +1447,11 @@ def _manage_hierarchic_fields(model, dct, and_reqs): container_ids += list(q.all()) main_req = Q(**{req + "__in": container_ids}) and_reqs.append(main_req) + continue if req.endswith("precise_town_id"): - val = _clean_type_val(dct.pop(req)).strip('"') - if val.startswith('"') and val.endswith('"'): - val = val[1:-1] - vals = [v.replace('"', "") for v in val.split(";")] - town_ids = [] - for val in vals: - q = Town.objects.filter(cached_label__iexact=val).values_list( - "id", flat=True) - if not q.count(): - continue - town_id = q.all()[0] - town_ids.append(town_id) - reqs = Q(**{req: val}) - for rel_query in ("parents__", "children__"): - for idx in range(HIERARCHIC_LEVELS): - k = rel_query * (idx + 1) + "pk" - q = Town.objects.filter( - **{k: town_id}).values_list("id", flat=True) - if not q.count(): - break - town_ids += list(q.all()) - main_req = Q(**{req + "__in": town_ids}) - and_reqs.append(main_req) - + _manage_hierarchic_precise_town(req, dct, and_reqs) + continue elif ( req.endswith("town__pk") or req.endswith("towns__pk") |