more sorting

This commit is contained in:
j 2011-01-05 18:36:09 +05:30
parent 786ca6596e
commit b234c9d50c
3 changed files with 68 additions and 264 deletions

View file

@ -40,6 +40,7 @@ def parseCondition(condition):
'person': 'string', 'person': 'string',
'text': 'string', 'text': 'string',
'year': 'string', 'year': 'string',
'length': 'string',
}.get(key_type, key_type) }.get(key_type, key_type)
if key_type == "string": if key_type == "string":

View file

@ -27,101 +27,6 @@ from annotaion.models import Annotation, Layer
from person.models import get_name_sort from person.models import get_name_sort
from app.models import site_config from app.models import site_config
def siteJson():
r = {}
r['findKeys'] = [{"id": "all", "title": "All"}]
for p in Property.objects.all():
if p.find:
title = p.title
if not title:
title = p.name.capitalize()
f = {"id": p.name, "title": title}
f['autocomplete'] = p.autocomplete
r['findKeys'].append(f)
r['groups'] = [p.name for p in Property.objects.filter(group=True)]
r['layers'] = [l.json() for l in Layer.objects.all()]
r['itemViews'] = [
{"id": "info", "title": "Info"},
{"id": "statistics", "title": "Statistics"},
{"id": "clips", "title": "Clips"},
{"id": "timeline", "title": "Timeline"},
{"id": "map", "title": "Map"},
{"id": "calendar", "title": "Calendar"},
{"id": "files", "title": "Files", "admin": True}
]
r['listViews'] = [
{"id": "list", "title": "as List"},
{"id": "icons", "title": "as Icons"},
{"id": "info", "title": "with Info"},
{"id": "clips", "title": "with Clips"},
{"id": "timelines", "title": "with Timelines"},
{"id": "maps", "title": "with Maps"},
{"id": "calendars", "title": "with Calendars"},
{"id": "clip", "title": "as Clips"},
{"id": "map", "title": "on Map"},
{"id": "calendar", "title": "on Calendar"}
]
r['site'] = {
"name": settings.SITENAME,
"id": settings.SITEID,
"url": settings.URL
}
r['sections'] = [
{"id": "history", "title": "History"},
{"id": "lists", "title": "My Lists"},
{"id": "public", "title": "Public Lists"},
{"id": "featured", "title": "Featured Lists"}
]
r['sortKeys'] = []
for p in Property.objects.exclude(sort=''):
title = p.title
if not title:
title = p.name.capitalize()
f = {
"id": p.name,
"title": title,
"operator": p.operator,
"align": p.align,
"width": p.width,
}
if not p.removable:
f['removable'] = False
r['sortKeys'].append(f)
r['sortKeys'].append([{"id": "id", "title": "ID", "operator": "", "align": "left", "width": 90}])
r['totals'] = [{"id": "items"}]
for p in Property.objects.filter(totals=True):
f = {'id': p.name, 'admin': p.admin}
r['totals'].append(f)
#FIXME: defaults should also be populated from properties
r["user"] = {
"group": "guest",
"preferences": {},
"ui": {
"columns": ["id"] + [p.name for p in Property.objects.filter(default=True)],
"findQuery": {"conditions": [], "operator": ""},
"groupsQuery": {"conditions": [], "operator": "|"},
"groupsSize": 128,
"itemView": "timeline",
"listQuery": {"conditions": [], "operator": ""},
"listsSize": 192,
"listView": "icons",
"sections": ["history", "lists", "public", "featured"],
"showGroups": True,
"showInfo": True,
"showLists": True,
"showMovies": True,
"sort": settings.DEFAULT_SORT,
"theme": settings.DEFAULT_THEME
},
"username": ""
}
return r
def get_item(info): def get_item(info):
''' '''
@ -171,54 +76,7 @@ def get_item(info):
return item return item
class Property(models.Model):
class Meta:
ordering = ('position', )
verbose_name_plural = "Properties"
name = models.CharField(null=True, max_length=255, unique=True)
title = models.CharField(null=True, max_length=255, blank=True)
#text, string, string from list(fixme), event, place, person
type = models.CharField(null=True, max_length=255)
array = models.BooleanField(default=False)
position = models.IntegerField(default=0)
width = models.IntegerField(default=180)
align = models.CharField(null=True, max_length=255, default='left')
operator = models.CharField(null=True, max_length=5, default='', blank=True)
default = models.BooleanField('Enabled by default', default=False)
removable = models.BooleanField(default=True)
#sort values: title, string, integer, float, date
sort = models.CharField(null=True, max_length=255, blank=True)
find = models.BooleanField(default=False)
autocomplete = models.BooleanField(default=False)
group = models.BooleanField(default=False)
totals = models.BooleanField(default=False)
admin = models.BooleanField(default=False)
def __unicode__(self):
if self.title:
return self.title
return self.name
def json(self):
j = {}
for key in ('type', 'sort', 'title', 'array', 'totals', 'admin'):
value = getattr(self, key)
if value:
j[key] = value
return j
def save(self, *args, **kwargs):
if not self.title:
self.title = self.name.capitalize()
super(Property, self).save(*args, **kwargs)
class Item(models.Model): class Item(models.Model):
person_keys = ('director', 'writer', 'producer', 'editor', 'cinematographer', 'actor', 'character')
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True) modified = models.DateTimeField(auto_now=True)
published = models.DateTimeField(default=datetime.now, editable=False) published = models.DateTimeField(default=datetime.now, editable=False)
@ -441,41 +299,32 @@ class Item(models.Model):
def get_json(self, fields=None): def get_json(self, fields=None):
item = {} item = {}
for key in self._public_fields: item.update(self.external_data)
pub_key = self._public_fields.get(key, key) item.update(self.data)
if not fields or pub_key in fields: for key in site_config['keys'].keys():
if hasattr(self, key): if key not in item:
value = getattr(self, key) value = self.get(key)
else: #also get values from sort table, i.e. numberof values
value = self.get(key) if not value and self.sort and hasattr(self.sort, key):
if callable(value): if hasattr(self.sort, '%s_desc'%key):
item[pub_key] = value() if getattr(self.sort, key) == getattr(self.sort, '%s_desc'%key):
else: value = getattr(self.sort, key)
item[pub_key] = value else:
value = getattr(self.sort, key)
if value:
item[key] = value
#format datetime values
for key in item:
if isinstance(item[key], datetime):
item[key] = item[key].strftime('%Y-%m-%dT%H:%M:%SZ')
if not fields: if not fields:
item['stream'] = self.get_stream() item['stream'] = self.get_stream()
item['poster'] = self.get_poster() item['poster'] = self.get_poster()
item['posters'] = self.get_posters() item['posters'] = self.get_posters()
if fields:
for f in fields:
if f.endswith('.length') and f[:-7] in ('cast', 'genre', 'trivia'):
item[f] = getattr(self.sort, f[:-7])
return item return item
def fields(self):
fields = {}
for f in self._meta.fields:
if f.name in self._public_fields:
fields[f.name] = {}
fields[f.name]['order'] = 'desc'
fields[f.name]['type'] = type(f)
return fields
fields = classmethod(fields)
def oxid(self):
return utils.oxid(self.get('title', ''), self.get('director', []), str(self.get('year', '')),
self.get('series_title', ''), self.get('episode_title', ''),
self.get('season', ''), self.get('episode', ''))
def oxdb_id(self): def oxdb_id(self):
return utils.oxdb_id(self.get('title', ''), self.get('director', []), str(self.get('year', '')), return utils.oxdb_id(self.get('title', ''), self.get('director', []), str(self.get('year', '')),
@ -496,11 +345,9 @@ class Item(models.Model):
else: else:
f.delete() f.delete()
#FIXME: use site_config
save('title', '\n'.join([self.get('title'), self.get('original_title', '')])) save('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()])
for key in self.facet_keys: for key in self.facet_keys:
if key == 'character': if key == 'character':
values = self.get('cast', '') values = self.get('cast', '')
@ -515,6 +362,7 @@ class Item(models.Model):
save(key, '|%s|'%'|'.join(values)) save(key, '|%s|'%'|'.join(values))
else: else:
save(key, values) save(key, values)
save('summary', self.get('summary', '') + self.get('plot', '') + self.get('plot_outline', '')) save('summary', self.get('summary', '') + self.get('plot', '') + self.get('plot_outline', ''))
save('trivia', ' '.join(self.get('trivia', []))) save('trivia', ' '.join(self.get('trivia', [])))
save('location', '|%s|'%'|'.join(self.get('filming_locations', []))) save('location', '|%s|'%'|'.join(self.get('filming_locations', [])))
@ -567,24 +415,27 @@ class Item(models.Model):
) )
for key in site_config['sortKeys']: for key in site_config['sortKeys']:
name = key['id'] name = key['id']
source = key.get('key', name)
field_type = key['type'] field_type = key['type']
max_int = 9223372036854775807L
if name not in base_keys: if name not in base_keys:
if field_type == 'title': if field_type == 'title':
value = utils.sort_title(canonicalTitle(self.get(name))) value = utils.sort_title(canonicalTitle(self.get(source)))
value = utils.sort_string(value) value = utils.sort_string(value)
setattr(s, '%s_desc'%name, value) setattr(s, '%s_desc'%name, value)
if not value: if not value:
value = 'zzzzzzzzzzzzzzzzzzzzzzzzz' value = 'zzzzzzzzzzzzzzzzzzzzzzzzz'
setattr(s, name, value) setattr(s, name, value)
elif field_type == 'person': elif field_type == 'person':
value = sortNames(self.get(name, [])) value = sortNames(self.get(source, []))
value = utils.sort_string(value)[:955] value = utils.sort_string(value)[:955]
setattr(s, '%s_desc'%name, value) setattr(s, '%s_desc'%name, value)
if not value: if not value:
value = 'zzzzzzzzzzzzzzzzzzzzzzzzz' value = 'zzzzzzzzzzzzzzzzzzzzzzzzz'
setattr(s, name, value) setattr(s, name, value)
elif field_type == 'string': elif field_type == 'string':
value = self.get(name, u'') value = self.get(source, u'')
if isinstance(value, list): if isinstance(value, list):
value = u','.join(value) value = u','.join(value)
value = utils.sort_string(value)[:955] value = utils.sort_string(value)[:955]
@ -593,19 +444,27 @@ class Item(models.Model):
value = 'zzzzzzzzzzzzzzzzzzzzzzzzz' value = 'zzzzzzzzzzzzzzzzzzzzzzzzz'
setattr(s, name, value) setattr(s, name, value)
elif field_type == 'length': elif field_type == 'length':
setattr(s, name, len(self.get(name, ''))) #can be length of strings or length of arrays, i.e. keywords
elif field_type == 'integer': value = self.get(source, None)
max_int = 9223372036854775807L if not value:
value = self.get(name, -max_int) value = -max_int
if isinstance(value, list): else:
value = len(value) value = len(value)
setattr(s, name, value) setattr(s, '%s_desc'%name, value)
if value == -max_int: if value == -max_int:
value = max_int value = max_int
setattr(s, name, value)
elif field_type == 'integer':
value = self.get(source, -max_int)
if isinstance(value, list):
value = len(value)
setattr(s, '%s_desc'%name, value) setattr(s, '%s_desc'%name, value)
if value == -max_int:
value = max_int
setattr(s, name, value)
elif field_type == 'float': elif field_type == 'float':
max_float = 9223372036854775807L max_float = 9223372036854775807L
value = self.get(name, -max_float) value = self.get(source, -max_float)
if isinstance(value, list): if isinstance(value, list):
value = sum(value) value = sum(value)
setattr(s, name, value) setattr(s, name, value)
@ -613,7 +472,7 @@ class Item(models.Model):
value = max_float value = max_float
setattr(s, '%s_desc'%name, value) setattr(s, '%s_desc'%name, value)
elif field_type == 'words': elif field_type == 'words':
value = self.get(name, '') value = self.get(source, '')
if isinstance(value, list): if isinstance(value, list):
value = '\n'.join(value) value = '\n'.join(value)
if value: if value:
@ -622,13 +481,13 @@ class Item(models.Model):
value = 0 value = 0
setattr(s, name, value) setattr(s, name, value)
elif field_type == 'year': elif field_type == 'year':
value = self.get(name, '') value = self.get(source, '')
setattr(s, '%s_desc'%name, value) setattr(s, '%s_desc'%name, value)
if not value: if not value:
value = '9999' value = '9999'
setattr(s, name, value) setattr(s, name, value)
elif field_type == 'date': elif field_type == 'date':
value = self.get(name, None) value = self.get(source, None)
if isinstance(value, basestring): if isinstance(value, basestring):
value = datetime.strptime(value, '%Y-%m-%d') value = datetime.strptime(value, '%Y-%m-%d')
setattr(s, '%s_desc'%name, value) setattr(s, '%s_desc'%name, value)
@ -684,6 +543,7 @@ class Item(models.Model):
s.cutsperminute = 0 s.cutsperminute = 0
s.save() s.save()
def update_facets(self): def update_facets(self):
#FIXME: what to do with Unkown Director, Year, Country etc. #FIXME: what to do with Unkown Director, Year, Country etc.
for key in self.facet_keys: for key in self.facet_keys:
@ -921,6 +781,10 @@ class ItemFind(models.Model):
key = models.CharField(max_length=200, db_index=True) key = models.CharField(max_length=200, db_index=True)
value = models.TextField(blank=True) value = models.TextField(blank=True)
'''
ItemSort
table constructed based on info in site_config['sortKeys']
'''
attrs = { attrs = {
'__module__': 'item.models', '__module__': 'item.models',
'item': models.OneToOneField('Item', related_name='sort', primary_key=True), 'item': models.OneToOneField('Item', related_name='sort', primary_key=True),
@ -952,76 +816,14 @@ ItemSort = type('ItemSort', (models.Model,), attrs)
ItemSort.fields = filter(lambda x: not x.endswith('_desc'), [f.name for f in ItemSort._meta.fields]) ItemSort.fields = filter(lambda x: not x.endswith('_desc'), [f.name for f in ItemSort._meta.fields])
ItemSort.descending_fields = filter(lambda x: x.endswith('_desc'), [f.name for f in ItemSort._meta.fields]) ItemSort.descending_fields = filter(lambda x: x.endswith('_desc'), [f.name for f in ItemSort._meta.fields])
'''
class ItemSort(models.Model):
#FIXME: make sort based on site.json
"""
used to sort items, all sort values are in here
"""
item = models.OneToOneField('Item', related_name='sort', primary_key=True)
title = models.CharField(max_length=1000, db_index=True)
director = models.TextField(blank=True, db_index=True)
country = models.TextField(blank=True, db_index=True)
year = models.CharField(max_length=4, db_index=True)
producer = models.TextField(blank=True, db_index=True)
writer = models.TextField(blank=True, db_index=True)
editor = models.TextField(blank=True, db_index=True)
cinematographer = models.TextField(blank=True, db_index=True)
language = models.TextField(blank=True, db_index=True)
runtime = models.IntegerField(blank=True, null=True, db_index=True)
keywords = models.IntegerField(blank=True, db_index=True)
genre = models.TextField(blank=True, db_index=True)
cast = models.IntegerField(blank=True, db_index=True)
summary = models.IntegerField(blank=True, db_index=True)
trivia = models.IntegerField(blank=True, db_index=True)
connections = models.IntegerField(blank=True, db_index=True)
rating = models.FloatField(blank=True, db_index=True)
votes = models.IntegerField(blank=True, db_index=True)
scenes = models.IntegerField(blank=True, db_index=True)
dialog = models.IntegerField(null=True, blank=True, db_index=True)
words = models.IntegerField(null=True, blank=True, db_index=True)
wpm = models.IntegerField('Words per Minute', null=True, blank=True, db_index=True)
risk = models.IntegerField(null=True, blank=True, db_index=True)
itemId = models.CharField('ID', max_length=128, blank=True, db_index=True)
duration = models.FloatField(default=-1, db_index=True)
resolution = models.BigIntegerField(blank=True, db_index=True)
aspectratio = models.IntegerField('Aspect Ratio', blank=True, db_index=True)
bitrate = models.IntegerField(blank=True, db_index=True)
pixels = models.BigIntegerField(blank=True, db_index=True)
filename = models.CharField(max_length=1024, blank=True, db_index=True)
files = models.IntegerField(blank=True, db_index=True)
size = models.BigIntegerField(blank=True, db_index=True)
color = models.IntegerField(blank=True, db_index=True)
saturation = models.IntegerField(blank=True, db_index=True)
brightness = models.IntegerField(blank=True, db_index=True)
cuts = models.IntegerField(blank=True, db_index=True)
cutsperminute = models.FloatField(blank=True, db_index=True)
#required to move empty values to the bottom for both asc and desc sort
title_desc = models.CharField(max_length=1000, db_index=True)
director_desc = models.TextField(blank=True, db_index=True)
country_desc = models.TextField(blank=True, db_index=True)
year_desc = models.CharField(max_length=4, db_index=True)
producer_desc = models.TextField(blank=True, db_index=True)
writer_desc = models.TextField(blank=True, db_index=True)
editor_desc = models.TextField(blank=True, db_index=True)
cinematographer_desc = models.TextField(blank=True, db_index=True)
language_desc = models.TextField(blank=True, db_index=True)
ItemSort.fields = filter(lambda x: not x.endswith('_desc'), [f.name for f in ItemSort._meta.fields])
ItemSort.descending_fields = filter(lambda x: x.endswith('_desc'), [f.name for f in ItemSort._meta.fields])
'''
class Facet(models.Model): class Facet(models.Model):
'''
used for keys that can have multiple values like people, languages etc.
does not perform to well if total number of items goes above 10k
this happens for keywords in 0xdb right now
'''
class Meta: class Meta:
unique_together = ("item", "key", "value") unique_together = ("item", "key", "value")
@ -1032,7 +834,7 @@ class Facet(models.Model):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.value_sort: if not self.value_sort:
self.value_sort = self.value self.value_sort = utils.sort_string(self.value)
super(Facet, self).save(*args, **kwargs) super(Facet, self).save(*args, **kwargs)

View file

@ -78,22 +78,23 @@
{"id": "country", "title": "Country", "width": 120, "type": "string"}, {"id": "country", "title": "Country", "width": 120, "type": "string"},
{"id": "year", "title": "Year", "width": 60, "type": "year"}, {"id": "year", "title": "Year", "width": 60, "type": "year"},
{"id": "language", "title": "Language", "width": 120, "type": "string"}, {"id": "language", "title": "Language", "width": 120, "type": "string"},
{"id": "runtime", "title": "Runtime", "width": 60, "type": "integer"}, {"id": "runtime", "title": "Runtime", "width": 60, "type": "integer", "format": "duration"},
{"id": "writer", "title": "Writer", "width": 180, "type": "person"}, {"id": "writer", "title": "Writer", "width": 180, "type": "person"},
{"id": "producer", "title": "Producer", "width": 180, "type": "person"}, {"id": "producer", "title": "Producer", "width": 180, "type": "person"},
{"id": "cinematographer", "title": "Cinematographer", "width": 180, "type": "person"}, {"id": "cinematographer", "title": "Cinematographer", "width": 180, "type": "person"},
{"id": "editor", "title": "Editor", "width": 180, "type": "person"}, {"id": "editor", "title": "Editor", "width": 180, "type": "person"},
{"id": "actor", "title": "Number of Actors", "width": 60, "type": "person"}, {"id": "actor", "title": "Number of Actors", "width": 60, "type": "person"},
{"id": "genre", "title": "Genre", "width": 120, "type": "string"}, {"id": "genre", "title": "Genre", "width": 120, "type": "string"},
{"id": "keyword", "title": "Number of Keywords", "width": 60, "type": "integer"}, {"id": "numberofkeywords", "title": "Number of Keywords", "width": 60, "key": "keyword", "type": "length"},
{"id": "summary", "title": "Words in Summary", "width": 60, "type": "words"}, {"id": "wordsinsummary", "title": "Words in Summary", "width": 60, "key": "summary", "type": "words"},
{"id": "trivia", "title": "Words in Trivia", "width": 60, "type": "words"}, {"id": "wordsintrivia", "title": "Words in Trivia", "width": 60, "key": "trivia", "type": "words"},
{"id": "releasedate", "title": "Release Date", "width": 90, "type": "date"}, {"id": "releasedate", "title": "Release Date", "width": 90, "type": "date"},
{"id": "budget", "title": "Budget", "width": 90, "type": "integer"}, {"id": "budget", "title": "Budget", "width": 90, "type": "integer", "format": "currency"},
{"id": "gross", "title": "Gross", "width": 90, "type": "integer"}, {"id": "gross", "title": "Gross", "width": 90, "type": "integer", "format": "currency"},
{"id": "profit", "title": "Profit", "width": 90, "type": "integer"}, {"id": "profit", "title": "Profit", "width": 90, "type": "integer", "format": "currency"},
{"id": "rating", "title": "Rating", "width": 60, "type": "float"}, {"id": "rating", "title": "Rating", "width": 60, "type": "float"},
{"id": "votes", "title": "Votes", "width": 90, "type": "integer"}, {"id": "votes", "title": "Votes", "width": 90, "type": "integer"},
{"id": "id", "title": "ID", "width": 90, "type": "string"}, {"id": "id", "title": "ID", "width": 90, "type": "string"},
{"id": "aspectratio", "title": "Aspect Ratio", "width": 90, "type": "float"}, {"id": "aspectratio", "title": "Aspect Ratio", "width": 90, "type": "float"},
{"id": "duration", "title": "Duration", "width": 90, "type": "float"}, {"id": "duration", "title": "Duration", "width": 90, "type": "float"},
@ -137,7 +138,6 @@
"item": "", "item": "",
"itemView": "timeline", "itemView": "timeline",
"listQuery": {"conditions": [], "operator": ""}, "listQuery": {"conditions": [], "operator": ""},
"listsSize": 256,
"listView": "icons", "listView": "icons",
"section": "items", "section": "items",
"sections": ["history", "lists", "public", "featured"], "sections": ["history", "lists", "public", "featured"],
@ -146,6 +146,7 @@
"showInfo": true, "showInfo": true,
"showMovies": true, "showMovies": true,
"showSidebar": true, "showSidebar": true,
"sidebarSize": 256,
"sitePage": "home", "sitePage": "home",
"sort": [ "sort": [
{"key": "director", "operator": ""} {"key": "director", "operator": ""}