diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2021-02-12 17:06:06 +0100 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2021-02-28 12:15:24 +0100 |
commit | 3bbe9b6b0ed29709500d82c3b8122f8adb11d9ee (patch) | |
tree | 40b83b93c5fdf5bf7cca8634867f8fdfdcfcc6bf /archaeological_warehouse | |
parent | 13b9ef1c26bb89349a15be94db7d01512e270d5a (diff) | |
download | Ishtar-3bbe9b6b0ed29709500d82c3b8122f8adb11d9ee.tar.bz2 Ishtar-3bbe9b6b0ed29709500d82c3b8122f8adb11d9ee.zip |
Container autocomplete: improve search
Diffstat (limited to 'archaeological_warehouse')
-rw-r--r-- | archaeological_warehouse/tests.py | 9 | ||||
-rw-r--r-- | archaeological_warehouse/views.py | 136 |
2 files changed, 94 insertions, 51 deletions
diff --git a/archaeological_warehouse/tests.py b/archaeological_warehouse/tests.py index f6d877ec4..21833a08f 100644 --- a/archaeological_warehouse/tests.py +++ b/archaeological_warehouse/tests.py @@ -514,8 +514,8 @@ class ContainerTest(FindInit, TestCase): ) def test_container_search(self): - ct = models.ContainerType.objects.all()[0] - ct2 = models.ContainerType.objects.all()[0] + ct = models.ContainerType.objects.order_by("id").all()[0] + ct2 = models.ContainerType.objects.order_by("id").all()[1] container_1 = models.Container.objects.create( reference="Test", responsible=self.main_warehouse, location=self.main_warehouse, @@ -547,9 +547,8 @@ class ContainerTest(FindInit, TestCase): self.assertEqual(response.status_code, 200) c = json.loads(response.content.decode()) self.assertEqual(len(c), 1) - response = client.get( - url, - {"term": "{} Test {} Test 35000".format(ct.label, ct2.label)}) + full_path = "{} Test {} 35000".format(ct.label, ct2.label) + response = client.get(url, {"term": full_path}) self.assertEqual(response.status_code, 200) c = json.loads(response.content.decode()) self.assertEqual(len(c), 1) diff --git a/archaeological_warehouse/views.py b/archaeological_warehouse/views.py index efa5bdf19..a9d1bf409 100644 --- a/archaeological_warehouse/views.py +++ b/archaeological_warehouse/views.py @@ -113,63 +113,106 @@ def autocomplete_container(request, warehouse_id=None): containers += list(models.Container.objects.filter( query).values('id', 'cached_label')[:limit]) limit = 15 - len(containers) - splitted = [s for s in term.split(' ') if s] - if limit > 0: - if len(splitted) > 1 and not len(splitted) % 2: - # group by container type, ref tuple - groups = [(splitted[idx * 2], splitted[idx * 2 + 1]) - for idx in range(int(len(splitted) / 2))] + splitted = [s.lower() for s in term.split(' ') if s] + + if limit > 0 and len(splitted) > 1: + type_positions = [] # container_type ID, pos inf, pos sup + container_types = [ + (c[0], c[1]) + for c in models.ContainerType.objects.values_list("id", "label") + ] + for container_type_id, value in container_types: + if value.lower() in term.lower(): # container_type is in search q + values = [v.lower() for v in value.split(" ") if v] + + # verify that all term match in splitted + try: + index = splitted.index(values[0].lower()) + except ValueError: + index = None + index_is_ok = False + while not index_is_ok and index is not None: + for idx, v in enumerate(values): + try: + assert splitted[index + idx] == v + except (ValueError, AssertionError): + break + index_is_ok = True + if not index_is_ok: + try: + index = splitted.index(values[0].lower(), index + 1) + except ValueError: + index = None + if index_is_ok: + type_positions.append( + (container_type_id, index, index + len(values))) + + query = base_query + if not warehouse_id and type_positions and type_positions[0][1] > 0: + for idx in range(type_positions[0][1]): + query &= Q(location__name__icontains=splitted[idx]) + # group by container type, ref tuple + groups = [] + for idx, (container_type_id, pos_inf, pos_sup) \ + in enumerate(type_positions): + if len(type_positions) == idx + 1: # last + value = " ".join(splitted[pos_sup:]) + else: + value = " ".join(splitted[pos_sup:type_positions[idx + 1][1]]) + groups.append((container_type_id, value)) + if groups: query = base_query for idx, g in enumerate(reversed(groups)): base_key = "parent__" * idx - key1 = base_key + "container_type__label__unaccent__iexact" + key1 = base_key + "container_type_id" key2 = base_key + "reference__unaccent__iexact" query &= Q(**{key1: g[0], key2: g[1]}) - ids = set([c["id"] for c in containers]) + ids = {c["id"] for c in containers} containers += list(models.Container.objects.filter( query).exclude(pk__in=ids).values('id', 'cached_label')[ :limit]) - if len(splitted) > 1 and (15 - len(containers)) > 0: - # group to do a "type" "reference" search - for idx in range(1, len(splitted)): - group_1 = splitted[:idx] - group_2 = splitted[idx:] - extra = Q( - container_type__label__unaccent__iexact=" ".join(group_1), - reference__unaccent__iexact=" ".join(group_2)) - query = base_query & extra - ids = set([c["id"] for c in containers]) - containers += list(models.Container.objects.filter( - query).exclude(pk__in=ids).values('id', 'cached_label')[ - :limit]) - if (15 - len(containers)) <= 0: - break - if (15 - len(containers)) > 0: + if len(splitted) > 1 and len(containers) < 15: + # group to do a "type" "reference" search + for idx in range(1, len(splitted)): + group_1 = splitted[:idx] + group_2 = splitted[idx:] + extra = Q( + container_type__label__unaccent__iexact=" ".join(group_1), + reference__unaccent__iexact=" ".join(group_2)) + query = base_query & extra + ids = {c["id"] for c in containers} + containers += list(models.Container.objects.filter( + query).exclude(pk__in=ids).values('id', 'cached_label')[ + :limit]) + if len(containers) >= 15: + break + + if len(containers) < 15: + query = base_query + for q in splitted: + extra = Q(reference__unaccent__iexact=q) + query = query & extra + ids = {c["id"] for c in containers} + containers += list(models.Container.objects.filter( + query).exclude(pk__in=ids).values('id', 'cached_label')[:limit]) + limit = 15 - len(containers) + if limit > 0: query = base_query for q in splitted: - extra = Q(reference__unaccent__iexact=q) + extra = Q(container_type__label__unaccent__icontains=q) | \ + Q(container_type__reference__unaccent__icontains=q) | \ + Q(reference__unaccent__icontains=q) | \ + Q(cached_label__unaccent__icontains=q) + if not warehouse_id: + extra |= Q(location__name__unaccent=q) | Q( + location__town__unaccent=q) query = query & extra - ids = set([c["id"] for c in containers]) - containers += list(models.Container.objects.filter( - query).exclude(pk__in=ids).values('id', 'cached_label')[:limit]) - limit = 15 - len(containers) - if limit > 0: - query = base_query - for q in splitted: - extra = Q(container_type__label__unaccent__icontains=q) | \ - Q(container_type__reference__unaccent__icontains=q) | \ - Q(reference__unaccent__icontains=q) | \ - Q(cached_label__unaccent__icontains=q) - if not warehouse_id: - extra |= Q(location__name__unaccent=q) | Q( - location__town__unaccent=q) - query = query & extra - ids = set([c["id"] for c in containers]) - containers += list( - models.Container.objects.filter(query).exclude( - pk__in=ids - ).values('id', 'cached_label')[:limit]) + ids = {c["id"] for c in containers} + containers += list( + models.Container.objects.filter(query).exclude( + pk__in=ids + ).values('id', 'cached_label')[:limit]) data = json.dumps( [{'id': container['id'], 'value': container['cached_label']} for container in containers]) @@ -304,7 +347,8 @@ def container_treatment_add(request, pk, current_right=None): except models.Container.DoesNotExist: raise Http404() return treatment_add( - request, ",".join([str(f.pk) for f in container.finds.all()])) + request, ",".join(str(f.pk) for f in container.finds.all()) + ) """ warehouse_packaging_wizard = ItemSourceWizard.as_view([ |