pandora/pandora/item/managers.py
2010-12-07 00:31:41 +01:00

216 lines
6.1 KiB
Python

# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
import re
from datetime import datetime
from urllib2 import unquote
from ox.utils import json
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Q, Manager
import models
def keyType(key):
if key in ('released', ):
return "date"
if key in ('year', 'cast.length'):
return "int"
if key in ('rating', 'votes'):
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': 'itemId'}.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":
in_find=True
value_key = 'find__value'
if op == '=':
if k in models.Item.facet_keys:
in_find=False
v = models.Item.objects.filter(facets__key=k, facets__value=v)
k = 'id__in'
else:
value_key = 'find__value__iexact'
elif op == '^':
v = v[1:]
value_key = 'find__value__istartswith'
elif op == '$':
v = v[:-1]
value_key = 'find__value__iendswith'
else: # elif op == '~':
value_key = 'find__value__icontains'
k = str(k)
if exclude:
if in_find and not k.startswith('itemId'):
q = ~Q(**{'find__key':k, value_key:v})
else:
q = ~Q(**{k:v})
else:
if in_find and not k.startswith('itemId'):
q = Q(**{'find__key':k, value_key:v})
else:
q = Q(**{k:v})
return q
else: #number or date
#FIXME: this part needs to be moved to use key/value find db
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('.'))
if exclude: #!1960-1970
k1 = 'value__lt'
k2 = 'value__gte'
return Q(**{'find__key': k, k1:v1})|Q(**{'find__key': k, k2:v2})
else: #1960-1970
k1 = 'value__gte'
k2 = 'value__lt'
return Q(**{'find__key': k, k1:v1})&Q(**{'find__key': k, k2:v2})
else:
if keyType(k) == "date":
v = parseDate(v.split('.'))
if op == '=':
vk = 'value__exact'
elif op == '>':
vk = 'value__gt'
elif op == '>=':
vk = 'value__gte'
elif op == '<':
vk = 'value__lt'
elif op == '<=':
vk = 'value__lte'
vk = 'find__%s' % vk
vk = str(vk)
if exclude: #!1960
return ~Q(**{'find__key': k, vk:v})
else: #1960
return Q(**{'find__key': k, vk: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:
if condition.get('value', '') != '' or condition.get('operator', '') == '=':
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 ItemManager(Manager):
def get_query_set(self):
return super(ItemManager, self).get_query_set()
def filter_list(self, qs, l, user):
if l != "all":
l = l.split(":")
only_public = True
if not user.is_anonymous():
if len(l) == 1: l = [request.user.username] + l
if request.user.username == l[0]:
only_public = False
if len(l) == 2:
lqs = models.List.objects.filter(name=l[1], user__username=l[0])
if only_public:
lqs = qls.filter(public=True)
if lqs.count() == 1:
qs = qs.filter(listitem__list__id=lqs[0].id)
return qs
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()
#only include items that have hard metadata
qs = qs.filter(available=True)
conditions = parseConditions(data['query']['conditions'],
data['query'].get('operator', '&'))
if conditions:
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)
return qs