From f4bd971f0a36e883750632ce4e468d8a55a35072 Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Fri, 17 Jun 2011 09:44:45 +0200 Subject: [PATCH] filter annnotations --- pandora/annotation/managers.py | 154 +++++++++++++++++++++++++++++++++ pandora/annotation/models.py | 2 + pandora/annotation/views.py | 4 +- static/js/pandora/ui/list.js | 11 ++- 4 files changed, 168 insertions(+), 3 deletions(-) create mode 100644 pandora/annotation/managers.py diff --git a/pandora/annotation/managers.py b/pandora/annotation/managers.py new file mode 100644 index 00000000..119fe5db --- /dev/null +++ b/pandora/annotation/managers.py @@ -0,0 +1,154 @@ +# -*- coding: utf-8 -*- +# vi:si:et:sw=4:sts=4:ts=4 +from django.db.models import Q, Manager +from ox.django.query import QuerySet +import ox + +def parseCondition(condition, user): + ''' + condition: { + value: "war" + } + or + condition: { + key: "year", + value: "1970-1980, + operator: "!=" + } + ... + ''' + k = condition.get('key', 'name') + k = { + 'user': 'user__username', + }.get(k, k) + if not k: + k = 'name' + v = condition['value'] + op = condition.get('operator') + if not op: + op = '' + if op.startswith('!'): + op = op[1:] + exclude = True + else: + exclude = False + if op == '-': + q = parseCondition({'key': k, 'value': v[0], 'operator': '>='}, user) \ + & parseCondition({'key': k, 'value': v[1], 'operator': '<'}, user) + if exclude: + return ~q + else: + return q + if k == 'id': + v = ox.from32(v) + if isinstance(v, bool): #featured and public flag + key = k + elif k in ('lat', 'lng', 'area', 'south', 'west', 'north', 'east', 'matches', 'id'): + if op == '>': + key = '%s__gt'%k + elif op == '>=': + key = '%s__gte'%k + elif op == '<': + key = '%s__lt'%k + elif op == '<=': + key = '%s__lte'%k + else: #default is exact match + key = k + else: + if op == '=' or op == '^$': + key = '%s__iexact'%k + elif op == '^': + v = v[1:] + key = '%s__istartswith'%k + elif op == '$': + v = v[:-1] + key = '%s__iendswith'%k + else: # default + key = '%s__icontains'%k + + key = str(key) + if exclude: + q = ~Q(**{key: v}) + else: + q = Q(**{key: v}) + return q + +def parseConditions(conditions, operator, user): + ''' + conditions: [ + { + value: "war" + } + { + key: "year", + value: "1970-1980, + operator: "!=" + }, + { + key: "country", + value: "f", + operator: "^" + } + ], + operator: "&" + ''' + conn = [] + for condition in conditions: + if 'conditions' in condition: + q = parseConditions(condition['conditions'], + condition.get('operator', '&'), user) + if q: + conn.append(q) + pass + else: + if condition.get('value', '') != '' or \ + condition.get('operator', '') == '=': + conn.append(parseCondition(condition, user)) + if conn: + q = conn[0] + for c in conn[1:]: + if operator == '|': + q = q | c + else: + q = q & c + return q + return None + + + +class AnnotationManager(Manager): + + def get_query_set(self): + return QuerySet(self.model) + + def find(self, data, user): + ''' + query: { + conditions: [ + { + value: "war" + } + { + key: "year", + value: "1970-1980, + operator: "!=" + }, + { + key: "country", + value: "f", + operator: "^" + } + ], + operator: "&" + } + ''' + + #join query with operator + qs = self.get_query_set() + + conditions = parseConditions(data.get('query', {}).get('conditions', []), + data.get('query', {}).get('operator', '&'), + user) + if conditions: + qs = qs.filter(conditions) + return qs diff --git a/pandora/annotation/models.py b/pandora/annotation/models.py index 27cf66f9..3ceac44e 100644 --- a/pandora/annotation/models.py +++ b/pandora/annotation/models.py @@ -7,6 +7,7 @@ from django.contrib.auth.models import User import ox import utils +import managers def load_layers(layers): @@ -70,6 +71,7 @@ class Layer(models.Model): class Annotation(models.Model): + objects = managers.AnnotationManager() #FIXME: here having a item,start index would be good created = models.DateTimeField(auto_now_add=True) diff --git a/pandora/annotation/views.py b/pandora/annotation/views.py index 12bbbd92..6bffd96a 100644 --- a/pandora/annotation/views.py +++ b/pandora/annotation/views.py @@ -22,10 +22,10 @@ def parse_query(data, user): query = {} query['range'] = [0, 100] query['sort'] = [{'key':'in', 'operator':'+'}] - for key in ('value', 'layer', 'in', 'out'): + for key in ('keys', 'group', 'range', 'sort', 'query'): if key in data: query[key] = data[key] - query['qs'] = models.Annotation.objects.all() + query['qs'] = models.Annotation.objects.find(query, user) if 'itemQuery' in data: item_query = Item.objects.find({'query': data['itemQuery']}, user) query['qs'] = query['qs'].filter(item__in=item_query) diff --git a/static/js/pandora/ui/list.js b/static/js/pandora/ui/list.js index 8554b02c..8e48f668 100644 --- a/static/js/pandora/ui/list.js +++ b/static/js/pandora/ui/list.js @@ -113,8 +113,17 @@ pandora.ui.list = function(view) { // fixme: remove view argument }; }, items: function(data, callback) { + var itemQuery = pandora.Query.toObject(), + query = {conditions:[]}; + //fixme: can this be in pandora.Query? dont just check for subtitles + itemQuery.conditions.forEach(function(q) { + if(q.key == 'subtitles') { + query.conditions.push({key: 'value', value: q.value, operator: q.operator}); + } + }); pandora.api.findAnnotations($.extend(data, { - itemQuery: pandora.Query.toObject() + query: query, + itemQuery: itemQuery }), callback); }, keys: ['id', 'value', 'in', 'out', 'aspectRatio', 'item'],