forked from 0x2620/pandora
dynamic sort table, not creating so far, needs sqldiff to update
This commit is contained in:
parent
eacaa943d7
commit
508e84b73c
5 changed files with 267 additions and 94 deletions
|
@ -1,7 +1,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vi:si:et:sw=4:sts=4:ts=4
|
||||
from django.db import models
|
||||
import os
|
||||
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
from ox.utils import json
|
||||
|
||||
class Page(models.Model):
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
|
@ -19,3 +22,10 @@ class SiteSettings(models.Model):
|
|||
|
||||
def __unicode__(self):
|
||||
return self.key
|
||||
|
||||
with open(os.path.join(settings.PROJECT_ROOT, 'templates', 'site.json')) as f:
|
||||
site_config = json.load(f)
|
||||
site_config['keys'] = {}
|
||||
for key in site_config['sortKeys']:
|
||||
site_config['keys'][key['id']] = key
|
||||
|
||||
|
|
|
@ -7,16 +7,6 @@ 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: {
|
||||
|
@ -37,21 +27,32 @@ def parseCondition(condition):
|
|||
v = condition['value']
|
||||
op = condition.get('operator', None)
|
||||
if not op:
|
||||
op = '~'
|
||||
op = ''
|
||||
if op.startswith('!'):
|
||||
op = op[1:]
|
||||
exclude = True
|
||||
else:
|
||||
exclude = False
|
||||
if keyType(k) == "string":
|
||||
|
||||
key_type = models.site_config['keys'].get(k, 'string')
|
||||
return {
|
||||
'title': 'string',
|
||||
'person': 'string'
|
||||
}.get(key_type, key_type)
|
||||
|
||||
if key_type == "string":
|
||||
in_find=True
|
||||
value_key = 'find__value'
|
||||
if op == '=':
|
||||
if k in models.Item.facet_keys:
|
||||
in_find=False
|
||||
in_find = False
|
||||
if op == '=':
|
||||
v = models.Item.objects.filter(facets__key=k, facets__value=v)
|
||||
elif op == '^':
|
||||
v = models.Item.objects.filter(facets__key=k, facets__value__istartswith=v)
|
||||
elif op == '$':
|
||||
v = models.Item.objects.filter(facets__key=k, facets__value__iendswith=v)
|
||||
k = 'id__in'
|
||||
else:
|
||||
elif op == '=':
|
||||
value_key = 'find__value__iexact'
|
||||
elif op == '^':
|
||||
v = v[1:]
|
||||
|
@ -59,7 +60,7 @@ def parseCondition(condition):
|
|||
elif op == '$':
|
||||
v = v[:-1]
|
||||
value_key = 'find__value__iendswith'
|
||||
else: # elif op == '~':
|
||||
else: # default
|
||||
value_key = 'find__value__icontains'
|
||||
k = str(k)
|
||||
if exclude:
|
||||
|
@ -82,7 +83,7 @@ def parseCondition(condition):
|
|||
if op == '-':
|
||||
v1 = v[1]
|
||||
v2 = v[2]
|
||||
if keyType(k) == "date":
|
||||
if key_type == "date":
|
||||
v1 = parseDate(v1.split('.'))
|
||||
v2 = parseDate(v2.split('.'))
|
||||
|
||||
|
@ -95,7 +96,7 @@ def parseCondition(condition):
|
|||
k2 = 'value__lt'
|
||||
return Q(**{'find__key': k, k1: v1})&Q(**{'find__key': k, k2: v2})
|
||||
else:
|
||||
if keyType(k) == "date":
|
||||
if key_type == "date":
|
||||
v = parseDate(v.split('.'))
|
||||
if op == '=':
|
||||
vk = 'value__exact'
|
||||
|
@ -107,6 +108,8 @@ def parseCondition(condition):
|
|||
vk = 'value__lt'
|
||||
elif op == '<=':
|
||||
vk = 'value__lte'
|
||||
elif op == '':
|
||||
vk = 'value__exact'
|
||||
|
||||
vk = 'find__%s' % vk
|
||||
vk = str(vk)
|
||||
|
|
|
@ -6,6 +6,7 @@ from datetime import datetime
|
|||
import os.path
|
||||
import subprocess
|
||||
from glob import glob
|
||||
import unicodedata
|
||||
|
||||
from django.db import models
|
||||
from django.core.files.base import ContentFile
|
||||
|
@ -24,7 +25,7 @@ from archive import extract
|
|||
|
||||
from annotaion.models import Annotation, Layer
|
||||
from person.models import get_name_sort
|
||||
|
||||
from app.models import site_config
|
||||
|
||||
def siteJson():
|
||||
r = {}
|
||||
|
@ -218,7 +219,6 @@ class Property(models.Model):
|
|||
|
||||
class Item(models.Model):
|
||||
person_keys = ('director', 'writer', 'producer', 'editor', 'cinematographer', 'actor', 'character')
|
||||
facet_keys = person_keys + ('country', 'language', 'genre', 'keyword')
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
modified = models.DateTimeField(auto_now=True)
|
||||
published = models.DateTimeField(default=datetime.now, editable=False)
|
||||
|
@ -271,7 +271,19 @@ class Item(models.Model):
|
|||
|
||||
def update_imdb(self):
|
||||
if len(self.itemId) == 7:
|
||||
self.external_data = ox.web.imdb.Imdb(self.itemId)
|
||||
data = ox.web.imdb.Imdb(self.itemId)
|
||||
#FIXME: all this should be in ox.web.imdb.Imdb
|
||||
for key in ('directors', 'writers', 'editors', 'producers', 'cinematographers', 'languages', 'genres', 'keywords'):
|
||||
if key in data:
|
||||
data[key[:-1]] = data.pop(key)
|
||||
if 'countries' in data:
|
||||
data['country'] = data.pop('countries')
|
||||
if 'release date' in data:
|
||||
data['releasedate'] = min(data.pop('release date'))
|
||||
if 'plot' in data:
|
||||
data['summary'] = data.pop('plot')
|
||||
data['actor'] = [c[0] for c in data['cast']]
|
||||
self.external_data = data
|
||||
self.save()
|
||||
|
||||
def __unicode__(self):
|
||||
|
@ -517,36 +529,113 @@ class Item(models.Model):
|
|||
sort_value = ''
|
||||
return sort_value
|
||||
|
||||
#title
|
||||
title = canonicalTitle(self.get('title'))
|
||||
s.title = utils.sort_title(title)
|
||||
base_keys = (
|
||||
'id',
|
||||
'aspectratio',
|
||||
'duration',
|
||||
'color',
|
||||
'saturation',
|
||||
'brightness',
|
||||
'volume',
|
||||
'clips',
|
||||
'cuts',
|
||||
'cutsperminute',
|
||||
'words',
|
||||
'wordsperminute',
|
||||
'resolution',
|
||||
'pixels',
|
||||
'size',
|
||||
'bitrate',
|
||||
'files',
|
||||
'filename',
|
||||
'published',
|
||||
'modified',
|
||||
'popularity'
|
||||
)
|
||||
for key in site_config['sortKeys']:
|
||||
name = key['id']
|
||||
field_type = key['type']
|
||||
if name not in base_keys:
|
||||
if field_type == 'title':
|
||||
value = utils.sort_title(canonicalTitle(self.get(name)))
|
||||
value = unicodedata.normalize('NFKD', value)
|
||||
setattr(s, name, value)
|
||||
if not value:
|
||||
value = 'zzzzzzzzzzzzzzzzzzzzzzzzz'
|
||||
setattr(s, '%s_desc'%name, value)
|
||||
elif field_type == 'person':
|
||||
value = sortNames(self.get(name, []))
|
||||
value = unicodedata.normalize('NFKD', value)
|
||||
setattr(s, name, value)
|
||||
if not value:
|
||||
value = 'zzzzzzzzzzzzzzzzzzzzzzzzz'
|
||||
setattr(s, '%s_desc'%name, value)
|
||||
elif field_type == 'text':
|
||||
#FIXME: what use pural_key?
|
||||
value = self.get(name, '')
|
||||
if isinstance(value, list):
|
||||
value = ','.join(value)
|
||||
value = unicodedata.normalize('NFKD', value)
|
||||
setattr(s, name, value)
|
||||
if not value:
|
||||
value = 'zzzzzzzzzzzzzzzzzzzzzzzzz'
|
||||
setattr(s, '%s_desc'%name, value)
|
||||
elif field_type == 'length':
|
||||
setattr(s, name, len(self.get(name, '')))
|
||||
elif field_type == 'integer':
|
||||
max_int = 9223372036854775807L
|
||||
value = self.get(name, -max_int)
|
||||
if isinstance(value, list):
|
||||
value = len(value)
|
||||
setattr(s, name, value)
|
||||
if value == -max_int:
|
||||
value = max_int
|
||||
setattr(s, '%s_desc'%name, value)
|
||||
elif field_type == 'float':
|
||||
max_float = 9223372036854775807L
|
||||
value = self.get(name, -max_float)
|
||||
if isinstance(value, list):
|
||||
value = sum(value)
|
||||
setattr(s, name, value)
|
||||
if value == -max_float:
|
||||
value = max_float
|
||||
setattr(s, '%s_desc'%name, value)
|
||||
elif field_type == 'words':
|
||||
value = self.get(name, '')
|
||||
if isinstance(value, list):
|
||||
value = '\n'.join(value)
|
||||
if value:
|
||||
value = len(value.split(' '))
|
||||
else:
|
||||
value = 0
|
||||
setattr(s, name, value)
|
||||
elif field_type == 'year':
|
||||
value = self.get(name, '')
|
||||
setattr(s, name, value)
|
||||
if not value:
|
||||
value = '9999'
|
||||
setattr(s, '%s_desc'%name, value)
|
||||
elif field_type == 'date':
|
||||
value = self.get(name, None)
|
||||
if isinstance(value, basestring):
|
||||
value = datetime.strptime(value, '%Y-%m-%d')
|
||||
setattr(s, name, value)
|
||||
if not value:
|
||||
value = datetime.strptime('9999-12-12', '%Y-%m-%d')
|
||||
setattr(s, '%s_desc'%name, value)
|
||||
|
||||
s.country = ','.join(self.get('countries', []))
|
||||
s.year = self.get('year', '')
|
||||
s.year_desc = s.year
|
||||
#sort keys based on database, these will always be available
|
||||
s.id = self.itemId.replace('0x', 'xx')
|
||||
s.modified = self.modified
|
||||
s.modified_desc = self.modified
|
||||
s.published = self.published
|
||||
s.published_desc = self.published
|
||||
|
||||
for key in self.person_keys:
|
||||
setattr(s, key, sortNames(self.get(utils.plural_key(key), [])))
|
||||
|
||||
for key in ('language', 'country'):
|
||||
setattr(s, key, ','.join(self.get(utils.plural_key(key), [])))
|
||||
|
||||
s.runtime = self.get('runtime', 0)
|
||||
|
||||
for key in ('keywords', 'genres', 'cast', 'summary', 'trivia', 'connections'):
|
||||
setattr(s, key, len(self.get(key, '')))
|
||||
|
||||
s.itemId = self.itemId.replace('0x', 'xx')
|
||||
s.rating = self.get('rating', -1)
|
||||
s.votes = self.get('votes', -1)
|
||||
|
||||
# data from related subtitles
|
||||
s.scenes = 0 #FIXME
|
||||
s.dialog = 0 #FIXME
|
||||
s.words = 0 #FIXME
|
||||
s.wpm = 0 #FIXME
|
||||
s.risk = 0 #FIXME
|
||||
# data from related files
|
||||
# sort values based on data from videos
|
||||
s.words = 0 #FIXME: get words from all layers or something
|
||||
s.wordsperminute = 0
|
||||
s.clips = 0 #FIXME: get clips from all layers or something
|
||||
s.popularity = 0 #FIXME: get popularity from somewhere
|
||||
videos = self.main_videos()
|
||||
if len(videos) > 0:
|
||||
s.duration = sum([v.duration for v in videos])
|
||||
|
@ -557,8 +646,10 @@ class Item(models.Model):
|
|||
s.bitrate = videos[0].info['bitrate']
|
||||
s.pixels = sum([v.pixels for v in videos])
|
||||
s.filename = ' '.join([v.name for v in videos])
|
||||
s.filename_desc = ' '.join([v.name for v in videos])
|
||||
s.files = self.files.all().count()
|
||||
s.size = sum([v.size for v in videos]) #FIXME: only size of movies?
|
||||
s.volume = 0
|
||||
else:
|
||||
s.duration = 0
|
||||
s.resolution = 0
|
||||
|
@ -568,6 +659,7 @@ class Item(models.Model):
|
|||
s.filename = 0
|
||||
s.files = 0
|
||||
s.size = 0
|
||||
s.volume = 0
|
||||
|
||||
s.color = int(sum(self.data.get('color', [])))
|
||||
s.saturation = 0 #FIXME
|
||||
|
@ -578,14 +670,6 @@ class Item(models.Model):
|
|||
s.cutsperminute = s.cuts / (s.duration/60)
|
||||
else:
|
||||
s.cutsperminute = 0
|
||||
for key in ('title', 'language', 'country') + self.person_keys:
|
||||
setattr(s, '%s_desc'%key, getattr(s, key))
|
||||
if not getattr(s, key):
|
||||
setattr(s, key, u'zzzzzzzzzzzzzzzzzzzzzzzzz')
|
||||
if not s.year:
|
||||
s.year_desc = ''
|
||||
s.year = '9999'
|
||||
#FIXME: also deal with number based rows like genre, keywords etc
|
||||
s.save()
|
||||
|
||||
def update_facets(self):
|
||||
|
@ -781,6 +865,14 @@ class Item(models.Model):
|
|||
p.wait()
|
||||
return posters.keys()
|
||||
|
||||
Item.facet_keys = []
|
||||
Item.person_keys = []
|
||||
for key in site_config['findKeys']:
|
||||
name = key['id']
|
||||
if key.get('autocomplete', False) and not site_config['keys'].get(name, {'type': None})['type'] == 'title':
|
||||
Item.facet_keys.append(name)
|
||||
if name in site_config['keys'] and site_config['keys'][name]['type'] == 'person':
|
||||
Item.person_keys.append(name)
|
||||
|
||||
class ItemFind(models.Model):
|
||||
"""
|
||||
|
@ -796,7 +888,40 @@ class ItemFind(models.Model):
|
|||
key = models.CharField(max_length=200, db_index=True)
|
||||
value = models.TextField(blank=True)
|
||||
|
||||
attrs = {
|
||||
'__module__': 'item.models',
|
||||
'item': models.OneToOneField('Item', related_name='sort', primary_key=True),
|
||||
}
|
||||
for key in site_config['sortKeys']:
|
||||
name = key['id']
|
||||
field_type = key['type']
|
||||
if field_type in ('string', 'title'):
|
||||
attrs[name] = models.CharField(max_length=1000, db_index=True)
|
||||
attrs['%s_desc'%name] = models.CharField(max_length=1000, db_index=True)
|
||||
elif field_type == 'year':
|
||||
attrs[name] = models.CharField(max_length=4, db_index=True)
|
||||
attrs['%s_desc'%name] = models.CharField(max_length=4, db_index=True)
|
||||
elif field_type in ('text', 'person'):
|
||||
attrs[name] = models.TextField(blank=True, db_index=True)
|
||||
attrs['%s_desc'%name] = models.TextField(blank=True, db_index=True)
|
||||
elif field_type in ('integer', 'words', 'length'):
|
||||
attrs[name] = models.BigIntegerField(blank=True, db_index=True)
|
||||
attrs['%s_desc'%name] = models.BigIntegerField(blank=True, db_index=True)
|
||||
elif field_type == 'float':
|
||||
attrs[name] = models.FloatField(blank=True, db_index=True)
|
||||
attrs['%s_desc'%name] = models.FloatField(blank=True, db_index=True)
|
||||
elif field_type == 'date':
|
||||
attrs[name] = models.DateTimeField(blank=True, db_index=True)
|
||||
attrs['%s_desc'%name] = models.DateTimeField(blank=True, db_index=True)
|
||||
else:
|
||||
print field_type
|
||||
print key
|
||||
|
||||
ItemSort = type('ItemSort', (models.Model,), attrs)
|
||||
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 ItemSort(models.Model):
|
||||
#FIXME: make sort based on site.json
|
||||
"""
|
||||
|
@ -848,7 +973,6 @@ class ItemSort(models.Model):
|
|||
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)
|
||||
|
@ -862,25 +986,18 @@ class ItemSort(models.Model):
|
|||
|
||||
language_desc = models.TextField(blank=True, db_index=True)
|
||||
|
||||
_private_fields = ('id', 'item')
|
||||
#return available sort fields
|
||||
#FIXME: should return mapping name -> verbose_name
|
||||
def fields(self):
|
||||
fields = []
|
||||
for f in self._meta.fields:
|
||||
if f.name not in self._private_fields:
|
||||
name = f.verbose_name
|
||||
name = name[0].capitalize() + name[1:]
|
||||
fields.append(name)
|
||||
return tuple(fields)
|
||||
fields = classmethod(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])
|
||||
'''
|
||||
|
||||
class Facet(models.Model):
|
||||
class Meta:
|
||||
unique_together = ("item", "key", "value")
|
||||
|
||||
item = models.ForeignKey('Item', related_name='facets')
|
||||
key = models.CharField(max_length=200, db_index=True)
|
||||
value = models.CharField(max_length=200)
|
||||
value_sort = models.CharField(max_length=200)
|
||||
value = models.CharField(max_length=200, db_index=True)
|
||||
value_sort = models.CharField(max_length=200, db_index=True)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.value_sort:
|
||||
|
|
|
@ -201,3 +201,4 @@ def sort_title(title):
|
|||
#pad numbered titles
|
||||
title = re.sub('(\d+)', lambda x: '%010d' % int(x.group(0)), title)
|
||||
return title.strip()
|
||||
|
||||
|
|
|
@ -42,13 +42,14 @@ def _order_query(qs, sort, prefix='sort__'):
|
|||
sort.append({'operator': '+', 'key': 'director'})
|
||||
sort.append({'operator': '-', 'key': 'year'})
|
||||
sort.append({'operator': '+', 'key': 'title'})
|
||||
|
||||
|
||||
for e in sort:
|
||||
operator = e['operator']
|
||||
if operator != '-':
|
||||
operator = ''
|
||||
key = {'id': 'itemId'}.get(e['key'], e['key'])
|
||||
#FIXME: this should be a property of models.ItemSort!!!
|
||||
if operator=='-' and key in ('title', 'director', 'writer', 'producer', 'editor', 'cinematographer', 'language', 'country', 'year'):
|
||||
if operator=='-' and '%s_desc'%key in models.ItemSort.descending_fields:
|
||||
key = '%s_desc' % key
|
||||
order = '%s%s%s' % (operator, prefix, key)
|
||||
order_by.append(order)
|
||||
|
@ -150,35 +151,33 @@ Positions
|
|||
if 'sort' in query:
|
||||
if len(query['sort']) == 1 and query['sort'][0]['key'] == 'items':
|
||||
if query['group'] == "year":
|
||||
query['sort'].append({'key': 'name', 'operator':'-'})
|
||||
order_by = query['sort'][0]['operator'] == '-' and 'items' or '-items'
|
||||
else:
|
||||
query['sort'].append({'key': 'name', 'operator':'+'})
|
||||
order_by = query['sort'][0]['operator'] == '-' and '-items' or 'items'
|
||||
if query['group'] != "keyword":
|
||||
order_by = (order_by, 'value_sort')
|
||||
else:
|
||||
query['sort'] = [{'key': 'name', 'operator':'+'}]
|
||||
order_by = (order_by,)
|
||||
else:
|
||||
order_by = query['sort'][0]['operator'] == '-' and '-value_sort' or 'value_sort'
|
||||
order_by = (order_by, 'items')
|
||||
else:
|
||||
order_by = ('-value_sort', 'items')
|
||||
response['data']['items'] = []
|
||||
items = 'items'
|
||||
item_qs = query['qs']
|
||||
qs = models.Facet.objects.filter(key=query['group']).filter(item__id__in=item_qs)
|
||||
qs = qs.values('value').annotate(items=Count('id')).order_by()
|
||||
name = 'value'
|
||||
name_sort = 'value_sort'
|
||||
qs = qs.values('value').annotate(items=Count('id')).order_by(**order_by)
|
||||
|
||||
#replace normalized items/name sort with actual db value
|
||||
for i in range(0, len(query['sort'])):
|
||||
if query['sort'][i]['key'] == 'name':
|
||||
query['sort'][i]['key'] = name_sort
|
||||
elif query['sort'][i]['key'] == 'items':
|
||||
query['sort'][i]['key'] = items
|
||||
qs = _order_query(qs, query['sort'], prefix='')
|
||||
if 'ids' in query:
|
||||
#FIXME: this does not scale for larger results
|
||||
response['data']['positions'] = {}
|
||||
ids = [j[name] for j in qs]
|
||||
ids = [j['value'] for j in qs]
|
||||
response['data']['positions'] = _get_positions(ids, query['ids'])
|
||||
|
||||
elif 'range' in data:
|
||||
qs = qs[query['range'][0]:query['range'][1]]
|
||||
response['data']['items'] = [{'name': i[name], 'items': i[items]} for i in qs]
|
||||
response['data']['items'] = [{'name': i['value'], 'items': i[items]} for i in qs]
|
||||
else:
|
||||
response['data']['items'] = qs.count()
|
||||
elif 'ids' in query:
|
||||
|
@ -222,6 +221,49 @@ Positions
|
|||
|
||||
actions.register(find)
|
||||
|
||||
def autocomplete(request):
|
||||
'''
|
||||
param data
|
||||
key
|
||||
value
|
||||
operator '', '^', '$'
|
||||
range
|
||||
return
|
||||
'''
|
||||
data = json.loads(request.POST['data'])
|
||||
if not 'range' in data:
|
||||
data['range'] = [0, 10]
|
||||
op = data.get('operator', '')
|
||||
|
||||
if models.site_config['keys'][data['key']]['type'] == 'title':
|
||||
qs = models.Item.objects.filter(available=True) #does this need more limiting? user etc
|
||||
if data['value']:
|
||||
if op == '':
|
||||
qs = qs.filter(find__key=data['key'], find__value__icontains=data['value'])
|
||||
elif op == '^':
|
||||
qs = qs.filter(find__key=data['key'], find__value__istartswith=data['value'])
|
||||
elif op == '$':
|
||||
qs = qs.filter(find__key=data['key'], find__value__iendswith=data['value'])
|
||||
qs = qs.order_by('-sort__%s'%models.site_config['keys'][data['key']]['autocompleteSortKey'])
|
||||
qs = qs[data['range'][0]:data['range'][1]]
|
||||
response = json_response({})
|
||||
response['data']['items'] = [i.get(data['key']) for i in qs]
|
||||
else:
|
||||
qs = models.Facet.objects.filter(key=data['key'])
|
||||
if data['value']:
|
||||
if op == '':
|
||||
qs = qs.filter(value__icontains=data['value'])
|
||||
elif op == '^':
|
||||
qs = qs.filter(value__istartswith=data['value'])
|
||||
elif op == '$':
|
||||
qs = qs.filter(value__iendswith=data['value'])
|
||||
qs = qs.values('value').annotate(items=Count('id')).order_by('-items')
|
||||
qs = qs[data['range'][0]:data['range'][1]]
|
||||
response = json_response({})
|
||||
response['data']['items'] = [i['value'] for i in qs]
|
||||
return render_to_json_response(response)
|
||||
actions.register(autocomplete)
|
||||
|
||||
|
||||
def getItem(request):
|
||||
'''
|
||||
|
|
Loading…
Reference in a new issue