summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--archaeological_finds/tests.py39
-rw-r--r--archaeological_finds/views.py29
-rw-r--r--ishtar_common/views_item.py69
3 files changed, 106 insertions, 31 deletions
diff --git a/archaeological_finds/tests.py b/archaeological_finds/tests.py
index 3c9995632..d9b79be89 100644
--- a/archaeological_finds/tests.py
+++ b/archaeological_finds/tests.py
@@ -937,6 +937,45 @@ class FindSearchTest(FindInit, TestCase):
self._test_search(c, result)
+class FindAutocompleteTest(FindInit, TestCase):
+ fixtures = WAREHOUSE_FIXTURES
+ model = models.Find
+
+ def setUp(self):
+ self.create_finds(force=True)
+ self.create_finds(force=True)
+ self.create_finds(force=True)
+ self.create_finds(force=True)
+ self.username = 'myuser'
+ self.password = 'mypassword'
+ User.objects.create_superuser(self.username, 'myemail@test.com',
+ self.password)
+ self.client = Client()
+
+ def test_autocomplete(self):
+ find = self.finds[0]
+ find.label = "test 012"
+ find.save()
+ find2 = self.finds[1]
+ find2.label = "test 12"
+ find2.save()
+ find3 = self.finds[2]
+ find3.label = "test 1"
+ find3.save()
+ find4 = self.finds[3]
+ find4.label = "test 0120"
+ find4.save()
+ c = Client()
+ c.login(username=self.username, password=self.password)
+ response = c.get(reverse('autocomplete-find') + "?term=12")
+ self.assertEqual(response.status_code, 200)
+ res = json.loads(response.content)
+ self.assertEqual(len(res), 3)
+ self.assertEqual(res[0]['id'], find2.pk) # " 12" - startswith
+ self.assertEqual(res[1]['id'], find.pk) # 12 - endswith
+ self.assertEqual(res[2]['id'], find4.pk) # 12 - contains
+
+
class FindPermissionTest(FindInit, TestCase):
fixtures = FIND_FIXTURES
model = models.Find
diff --git a/archaeological_finds/views.py b/archaeological_finds/views.py
index 72d02305c..9e1a22a2a 100644
--- a/archaeological_finds/views.py
+++ b/archaeological_finds/views.py
@@ -17,6 +17,7 @@
# See the file COPYING for details.
+from collections import OrderedDict
import json
from django.core.exceptions import PermissionDenied
@@ -42,7 +43,7 @@ from archaeological_finds import forms
from ishtar_common.views import get_autocomplete_generic, IshtarMixin, \
LoginRequiredMixin, QAItemEditForm, QAItemForm
from ishtar_common.views_item import display_item, get_item, show_item, \
- revert_item, get_autocomplete_item, get_autocomplete_query
+ revert_item, get_autocomplete_item, get_autocomplete_queries
from archaeological_operations.wizards import AdministrativeActDeletionWizard
from archaeological_finds import wizards
@@ -152,17 +153,23 @@ def autocomplete_findbasket(request, current_right=None):
if not request.GET.get('term'):
return HttpResponse(content_type='text/plain')
- query = get_autocomplete_query(request, ['label'])
limit = 20
- query = query & models.FindBasket.get_write_query_owns(
- request.user.ishtaruser)
- items = models.FindBasket.objects.filter(query).distinct().order_by(
- 'label')[:limit]
- data = json.dumps(
- [{'id': item.pk,
- 'value': u"{} - {}".format(item.label, item.user)[:60]}
- for item in items]
- )
+ result = OrderedDict()
+ for query in get_autocomplete_queries(request, ['label']):
+ query = query & models.FindBasket.get_write_query_owns(
+ request.user.ishtaruser)
+ objects = models.FindBasket.objects.filter(query).distinct().order_by(
+ 'label')[:limit]
+ for obj in objects:
+ if obj.id not in list(result.keys()):
+ result[obj.id] = u"{} - {}".format(obj.label, obj.user)[:60]
+ limit -= 1
+ if not limit:
+ break
+ if not limit:
+ break
+ data = json.dumps([{'id': obj[0], 'value': obj[1]}
+ for obj in list(result.items())])
return HttpResponse(data, content_type='text/plain')
diff --git a/ishtar_common/views_item.py b/ishtar_common/views_item.py
index 57d778459..96190f083 100644
--- a/ishtar_common/views_item.py
+++ b/ishtar_common/views_item.py
@@ -1,6 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
+from collections import OrderedDict
from copy import copy, deepcopy
import csv
import datetime
@@ -67,33 +68,61 @@ CURRENT_ITEM_KEYS = (
CURRENT_ITEM_KEYS_DICT = dict(CURRENT_ITEM_KEYS)
-def get_autocomplete_query(request, label_attributes, extra=None):
- q = request.GET.get('term') or ""
+def get_autocomplete_queries(request, label_attributes, extra=None):
if not label_attributes:
- return Q(pk__isnull=True)
- query = Q()
- if extra:
- query = Q(**extra)
- for q in q.split(' '):
- if not q:
- continue
- sub_q = Q(**{label_attributes[0] + "__icontains": q})
- for other_label in label_attributes[1:]:
- sub_q = sub_q | Q(**{other_label + "__icontains": q})
- query = query & sub_q
- return query
+ return [Q(pk__isnull=True)]
+ base_q = request.GET.get('term') or ""
+ queries = []
+ splited_q = base_q.split(' ')
+ for value_prefix, query_suffix, query_endswith in (
+ ('', '__startswith', True), # starts with
+ (' ', '__icontains', True), # contain a word which starts with
+ ('', '__endswith', False), # ends with
+ ('', '__icontains', False)): # contains
+ alt_queries = [None]
+ if len(splited_q) == 1 and query_endswith:
+ alt_queries = ["__endswith", None]
+ for alt_query in alt_queries:
+ query = Q()
+ if extra:
+ query = Q(**extra)
+ for q in splited_q:
+ if not q:
+ continue
+ sub_q = Q(
+ **{label_attributes[0] + query_suffix: value_prefix + q})
+ if alt_query:
+ sub_q &= Q(
+ **{label_attributes[0] + alt_query: q}
+ )
+ for other_label in label_attributes[1:]:
+ sub_q = sub_q | Q(
+ **{other_label + query_suffix: value_prefix + q})
+ query = query & sub_q
+ queries.append(query)
+ return queries
def get_autocomplete_item(model, extra=None):
if not extra:
extra = {}
- def func(request, current_right=None):
- query = get_autocomplete_query(request, ['cached_label'], extra=extra)
- limit = 20
- objects = model.objects.filter(query)[:limit]
- data = json.dumps([{'id': obj.pk, 'value': obj.cached_label}
- for obj in objects])
+ def func(request, current_right=None, limit=20):
+ result = OrderedDict()
+ for query in get_autocomplete_queries(request, ['cached_label'],
+ extra=extra):
+ objects = model.objects.filter(query).values(
+ 'cached_label', 'id')[:limit]
+ for obj in objects:
+ if obj["id"] not in list(result.keys()):
+ result[obj["id"]] = obj["cached_label"]
+ limit -= 1
+ if not limit:
+ break
+ if not limit:
+ break
+ data = json.dumps([{'id': obj[0], 'value': obj[1]}
+ for obj in list(result.items())])
return HttpResponse(data, content_type='text/plain')
return func