From bca6408974797b306a7c6db50203cb3be827fbe3 Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Wed, 14 Jul 2010 16:35:10 +0200 Subject: [PATCH] cleanup, allow nested conditions --- pandora/backend/managers.py | 219 ++++++++++++++++++++++-------------- pandora/backend/models.py | 33 +++--- pandora/backend/views.py | 2 - 3 files changed, 151 insertions(+), 103 deletions(-) diff --git a/pandora/backend/managers.py b/pandora/backend/managers.py index bc563701a..adc624683 100644 --- a/pandora/backend/managers.py +++ b/pandora/backend/managers.py @@ -21,6 +21,135 @@ def keyType(key): return "float" return "string" +def parseCondition(condition): + ''' + condition: { + value: "war" + } + or + condition: { + key: "year", + value: "1970-1980, + operator: "!=" + } + ... + ''' + + k = condition.get('key', 'all') + k = {'id': 'movieId'}.get(k, k) + if not k: k = 'all' + v = condition['value'] + op = condition.get('operator', None) + if not op: op = '~' + if op.startswith('!'): + op = op[1:] + exclude = True + else: + exclude = False + if keyType(k) == "string": + if op == '=': + if k in ('director', 'country', 'language', 'genre', + 'keywords', 'location', 'writer', 'producer', + 'editor', 'cinematographer'): + k = '%s__icontains' % k + v = u'|%s|'%v + else: + k = '%s__iexact' % k + elif op == '^': + v = v[1:] + k = '%s__istartswith' % k + elif op == '$': + v = v[:-1] + k = '%s__iendswith' % k + else: # elif op == '~': + k = '%s__icontains' % k + if not k.startswith('movieId'): + k = 'find__%s' % k + k = str(k) + if exclude: + return ~Q(**{k:v}) + else: + return Q(**{k:v}) + else: #number or date + def parseDate(d): + while len(d) < 3: + d.append(1) + return datetime(*[int(i) for i in d]) + if op == '-': + v1 = v[1] + v2 = v[2] + if keyType(k) == "date": + v1 = parseDate(v1.split('.')) + v2 = parseDate(v2.split('.')) + + k = 'find__%s' % k + if exclude: #!1960-1970 + k1 = str('%s__lt' % k) + k2 = str('%s__gte' % k) + return Q(**{k1:v1})|Q(**{k2:v2}) + else: #1960-1970 + k1 = str('%s__gte' % k) + k2 = str('%s__lt' % k) + return Q(**{k1:v1})&Q(**{k2:v2}) + else: + if keyType(k) == "date": + v = parseDate(v.split('.')) + if op == '=': + k = '%s__exact' % k + elif op == '>': + k = '%s__gt' % k + elif op == '>=': + k = '%s__gte' % k + elif op == '<': + k = '%s__lt' % k + elif op == '<=': + k = '%s__lte' % k + + k = 'find__%s' % k + k = str(k) + if exclude: #!1960 + return ~Q(**{k:v}) + else: #1960 + return Q(**{k:v}) + +def parseConditions(conditions, operator): + ''' + 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', '&')) + if q: conn.append(q) + pass + else: + conn.append(parseCondition(condition)) + if conn: + q = conn[0] + for c in conn[1:]: + if operator == '|': + q = q | c + else: + q = q & c + return q + return None + class MovieManager(Manager): def get_query_set(self): return super(MovieManager, self).get_query_set() @@ -59,100 +188,20 @@ class MovieManager(Manager): operator: "^" } ], - operator: "," + operator: "&" } ''' - query_operator = data['query'].get('operator', ',') - conditions = [] - for condition in data['query']['conditions']: - k = condition.get('key', 'all') - k = {'id': 'movieId'}.get(k, k) - if not k: k = 'all' - v = condition['value'] - op = condition.get('operator', None) - if not op: op = '~' - if op.startswith('!'): - op = op[1:] - exclude = True - else: - exclude = False - if keyType(k) == "string": - if op == '=': - if k in ('director', 'country', 'language', 'genre', 'keywords', 'location', 'writer', 'producer', 'editor', 'cinematographer'): - k = '%s__icontains' % k - v = u'|%s|'%v - else: - k = '%s__iexact' % k - elif op == '^': - v = v[1:] - k = '%s__istartswith' % k - elif op == '$': - v = v[:-1] - k = '%s__iendswith' % k - else: # elif op == '~': - k = '%s__icontains' % k - if not k.startswith('movieId'): - k = 'find__%s' % k - k = str(k) - if exclude: - conditions.append(~Q(**{k:v})) - else: - conditions.append(Q(**{k:v})) - else: #number or date - def parseDate(d): - while len(d) < 3: - d.append(1) - return datetime(*[int(i) for i in d]) - if op == '-': - v1 = v[1] - v2 = v[2] - if keyType(k) == "date": - v1 = parseDate(v1.split('.')) - v2 = parseDate(v2.split('.')) - - k = 'find__%s' % k - if exclude: #!1960-1970 - k1 = str('%s__lt' % k) - k2 = str('%s__gte' % k) - conditions.append(Q(**{k1:v1})|Q(**{k2:v2})) - else: #1960-1970 - k1 = str('%s__gte' % k) - k2 = str('%s__lt' % k) - conditions.append(Q(**{k1:v1})&Q(**{k2:v2})) - else: - if keyType(k) == "date": - v = parseDate(v.split('.')) - if op == '=': - k = '%s__exact' % k - elif op == '>': - k = '%s__gt' % k - elif op == '>=': - k = '%s__gte' % k - elif op == '<': - k = '%s__lt' % k - elif op == '<=': - k = '%s__lte' % k - - k = 'find__%s' % k - k = str(k) - if exclude: #!1960 - conditions.append(~Q(**{k:v})) - else: #1960 - conditions.append(Q(**{k:v})) #join query with operator qs = self.get_query_set() #only include movies that have hard metadata qs = qs.filter(available=True) + conditions = parseConditions(data['query']['conditions'], + data['query'].get('operator', '&')) if conditions: - q = conditions[0] - for c in conditions[1:]: - if query_operator == '|': - q = q | c - else: - q = q & c - qs = qs.filter(q) + qs = qs.filter(conditions) + #FIXME: lists are part of query now # filter list, works for own or public lists l = data.get('list', 'all') qs = self.filter_list(qs, l, user) diff --git a/pandora/backend/models.py b/pandora/backend/models.py index 984fe3929..eb22e9241 100644 --- a/pandora/backend/models.py +++ b/pandora/backend/models.py @@ -23,6 +23,11 @@ import load import utils import extract +def plural_key(term): + return { + 'country': 'countries', + }.get(term, term + 's') + def getMovie(info): ''' @@ -242,20 +247,19 @@ class Movie(models.Model): except MovieFind.DoesNotExist: f = MovieFind(movie=self) - f.title = self.get('title') + f.title = '\n'.join([self.get('title'), self.get('original_title', '')]) #FIXME: filter us/int title #f.title += ' '.join([t.title for t in self.alternative_titles()]) - f.director = '|%s|'%'|'.join(self.get('directors', [])) - f.country = '|%s|'%'|'.join(self.get('countries', [])) + f.year = self.get('year', '') - for key in ('language', 'writer', 'producer', 'editor', 'cinematographer'): - setattr(f, key, '|%s|'%'|'.join(self.get('%ss'%key, []))) + + for key in ('directors', 'country', 'language', 'writer', 'producer', + 'editor', 'cinematographer', 'genre', 'keyword'): + setattr(f, key, '|%s|'%'|'.join(self.get(plural_key(key), []))) f.actor = '|%s|'%'|'.join([i[0] for i in self.get('actor', [])]) f.character = '|%s|'%'|'.join([stripTagsl(i[1]) for i in self.get('actor', [])]) - f.genre = '|%s|'%'|'.join(self.get('genres', [])) - f.keyword = '|%s|'%'|'.join(self.get('keywords', [])) f.summary = self.get('plot', '') + self.get('plot_outline', '') f.trivia = ' '.join(self.get('trivia', [])) f.location = '|%s|'%'|'.join(self.get('filming_locations', [])) @@ -302,10 +306,11 @@ class Movie(models.Model): s.year = self.get('year', '') for key in ('director', 'writer', 'producer', 'editor', 'cinematographer'): - setattr(s, key, sortNames(self.get('%ss'%key, []))) + setattr(s, key, sortNames(self.get(plural_key(key), []))) + + for key in ('language', 'country'): + setattr(s, key, ','.join(self.get(plural_key(key), []))) - s.language = ','.join(self.get('languages', [])) - s.country = ','.join(self.get('countries', [])) s.runtime = self.get('runtime', 0) s.keywords = len(self.get('keywords', [])) @@ -347,12 +352,8 @@ class Movie(models.Model): def updateFacets(self): #"year", is extra is it? #FIXME: what to do with Unkown Director, Year, Country etc. - def plural(term): - return { - 'country': 'countries', - }.get(term, term + 's') - for key in ("director", "country", "language", "genre"): - current_values = self.get(plural(key), []) + for key in ("director", "country", 'writer', 'producer', 'editor', 'cinematographer', "language", "genre"): + current_values = self.get(plural_key(key), []) saved_values = [i.value for i in Facet.objects.filter(movie=self, key=key)] removed_values = filter(lambda x: x not in current_values, saved_values) if removed_values: diff --git a/pandora/backend/views.py b/pandora/backend/views.py index ec362577d..b918c661b 100644 --- a/pandora/backend/views.py +++ b/pandora/backend/views.py @@ -188,7 +188,6 @@ Positions query['sort'].append({'key': 'name', 'operator':'+'}) else: query['sort'] = [{'key': 'name', 'operator':'+'}] - #FIXME: also filter lists here response['data']['items'] = [] items = 'movies' movie_qs = query['qs'] @@ -237,7 +236,6 @@ Positions qs = qs[query['range'][0]:query['range'][1]] response['data']['items'] = [only_p(m['json']) for m in qs.values('json')] else: # otherwise stats - #movies = models.Movie.objects.filter(available=True) movies = query['qs'] files = File.objects.all().filter(movie__in=movies) r = files.aggregate(