findAnnotations: match some fields case-sensitively

Requiring layer to have the right case is consistent with
addAnnotation(), and means the _layer[_like] index can be used. In my
testing, if itemsQuery specifies a single item, then postgres doesn't
bother with the layer index anyway; but if not, it makes a pretty big
(~3×) difference.

Matching public_id and item__public_id case-sensitively also seems
reasonable (it's consistent with get() and getAnnotation()).

(Is lower() redundant for the case-insensitive comparisons? ie. is
UPPER(x.lower()) == UPPER(x)? I'm not sure, it's cheap, let's leave it.)
This commit is contained in:
Will Thompson 2016-04-04 14:25:23 +01:00
parent 8d1b4de337
commit b3df5b8d56
1 changed files with 22 additions and 4 deletions

View File

@ -7,6 +7,12 @@ from oxdjango.query import QuerySet
from item.utils import decode_id
case_sensitive_keys = (
'public_id',
'layer',
'item__public_id',
)
def parseCondition(condition, user):
'''
@ -53,14 +59,24 @@ def parseCondition(condition, user):
v = decode_id(v)
if isinstance(v, bool): #featured and public flag
key = k
elif k in ('lat', 'lng', 'area', 'south', 'west', 'north', 'east', 'matches',
'id', 'places__id', 'events__id'):
elif k in ('places__id', 'events__id'):
key = "%s%s" % (k, {
'>': '__gt',
'>=': '__gte',
'<': '__lt',
'<=': '__lte',
}.get(op, ''))
elif k in case_sensitive_keys:
key = "%s%s" % (k, {
'>': '__gt',
'>=': '__gte',
'<': '__lt',
'<=': '__lte',
'==': '__exact',
'=': '__contains',
'^': '__startswith',
'$': '__endswith',
}.get(op, '__contains'))
else:
key = "%s%s" % (k, {
'>': '__gt',
@ -75,7 +91,9 @@ def parseCondition(condition, user):
key = str(key)
if isinstance(v, unicode):
v = unicodedata.normalize('NFKD', v).lower()
v = unicodedata.normalize('NFKD', v)
if v not in case_sensitive_keys:
v = v.lower()
if exclude:
q = ~Q(**{key: v})
else:
@ -152,7 +170,7 @@ class AnnotationManager(Manager):
#join query with operator
qs = self.get_query_set()
conditions = parseConditions(data.get('query', {}).get('conditions', []),
data.get('query', {}).get('operator', '&'),
user)