summaryrefslogtreecommitdiff
path: root/archaeological_warehouse
diff options
context:
space:
mode:
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
commit0d860bb0211ce14bbb86ffe7411ec2853852b64d (patch)
tree40b83b93c5fdf5bf7cca8634867f8fdfdcfcc6bf /archaeological_warehouse
parent6e4f7a0390b7f49ce79f0e15e07e1d6df309f3ce (diff)
downloadIshtar-0d860bb0211ce14bbb86ffe7411ec2853852b64d.tar.bz2
Ishtar-0d860bb0211ce14bbb86ffe7411ec2853852b64d.zip
Container autocomplete: improve search
Diffstat (limited to 'archaeological_warehouse')
-rw-r--r--archaeological_warehouse/tests.py9
-rw-r--r--archaeological_warehouse/views.py136
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([