cleanup, allow nested conditions

This commit is contained in:
j 2010-07-14 16:35:10 +02:00
parent 4b7be5402a
commit bca6408974
3 changed files with 151 additions and 103 deletions

View file

@ -21,6 +21,135 @@ def keyType(key):
return "float" return "float"
return "string" 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): class MovieManager(Manager):
def get_query_set(self): def get_query_set(self):
return super(MovieManager, self).get_query_set() return super(MovieManager, self).get_query_set()
@ -59,100 +188,20 @@ class MovieManager(Manager):
operator: "^" 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 #join query with operator
qs = self.get_query_set() qs = self.get_query_set()
#only include movies that have hard metadata #only include movies that have hard metadata
qs = qs.filter(available=True) qs = qs.filter(available=True)
conditions = parseConditions(data['query']['conditions'],
data['query'].get('operator', '&'))
if conditions: if conditions:
q = conditions[0] qs = qs.filter(conditions)
for c in conditions[1:]:
if query_operator == '|':
q = q | c
else:
q = q & c
qs = qs.filter(q)
#FIXME: lists are part of query now
# filter list, works for own or public lists # filter list, works for own or public lists
l = data.get('list', 'all') l = data.get('list', 'all')
qs = self.filter_list(qs, l, user) qs = self.filter_list(qs, l, user)

View file

@ -23,6 +23,11 @@ import load
import utils import utils
import extract import extract
def plural_key(term):
return {
'country': 'countries',
}.get(term, term + 's')
def getMovie(info): def getMovie(info):
''' '''
@ -242,20 +247,19 @@ class Movie(models.Model):
except MovieFind.DoesNotExist: except MovieFind.DoesNotExist:
f = MovieFind(movie=self) 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 #FIXME: filter us/int title
#f.title += ' '.join([t.title for t in self.alternative_titles()]) #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', '') 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.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.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.summary = self.get('plot', '') + self.get('plot_outline', '')
f.trivia = ' '.join(self.get('trivia', [])) f.trivia = ' '.join(self.get('trivia', []))
f.location = '|%s|'%'|'.join(self.get('filming_locations', [])) f.location = '|%s|'%'|'.join(self.get('filming_locations', []))
@ -302,10 +306,11 @@ class Movie(models.Model):
s.year = self.get('year', '') s.year = self.get('year', '')
for key in ('director', 'writer', 'producer', 'editor', 'cinematographer'): 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.runtime = self.get('runtime', 0)
s.keywords = len(self.get('keywords', [])) s.keywords = len(self.get('keywords', []))
@ -347,12 +352,8 @@ class Movie(models.Model):
def updateFacets(self): def updateFacets(self):
#"year", is extra is it? #"year", is extra is it?
#FIXME: what to do with Unkown Director, Year, Country etc. #FIXME: what to do with Unkown Director, Year, Country etc.
def plural(term): for key in ("director", "country", 'writer', 'producer', 'editor', 'cinematographer', "language", "genre"):
return { current_values = self.get(plural_key(key), [])
'country': 'countries',
}.get(term, term + 's')
for key in ("director", "country", "language", "genre"):
current_values = self.get(plural(key), [])
saved_values = [i.value for i in Facet.objects.filter(movie=self, 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) removed_values = filter(lambda x: x not in current_values, saved_values)
if removed_values: if removed_values:

View file

@ -188,7 +188,6 @@ Positions
query['sort'].append({'key': 'name', 'operator':'+'}) query['sort'].append({'key': 'name', 'operator':'+'})
else: else:
query['sort'] = [{'key': 'name', 'operator':'+'}] query['sort'] = [{'key': 'name', 'operator':'+'}]
#FIXME: also filter lists here
response['data']['items'] = [] response['data']['items'] = []
items = 'movies' items = 'movies'
movie_qs = query['qs'] movie_qs = query['qs']
@ -237,7 +236,6 @@ Positions
qs = qs[query['range'][0]:query['range'][1]] qs = qs[query['range'][0]:query['range'][1]]
response['data']['items'] = [only_p(m['json']) for m in qs.values('json')] response['data']['items'] = [only_p(m['json']) for m in qs.values('json')]
else: # otherwise stats else: # otherwise stats
#movies = models.Movie.objects.filter(available=True)
movies = query['qs'] movies = query['qs']
files = File.objects.all().filter(movie__in=movies) files = File.objects.all().filter(movie__in=movies)
r = files.aggregate( r = files.aggregate(