136 lines
3.5 KiB
Python
136 lines
3.5 KiB
Python
import re
|
|
from django.core.urlresolvers import reverse
|
|
from django.core.serializers.json import DjangoJSONEncoder
|
|
from django.http import HttpResponse
|
|
from django.utils.encoding import smart_unicode, force_unicode
|
|
try:
|
|
import json
|
|
except ImportError:
|
|
from django.utils import simplejson as json
|
|
|
|
class LookupBase(object):
|
|
|
|
@classmethod
|
|
def name(cls):
|
|
app_name = cls.__module__.split('.')[-2].lower()
|
|
class_name = cls.__name__.lower()
|
|
name = u'%s-%s' % (app_name, class_name)
|
|
return name
|
|
|
|
@classmethod
|
|
def url(cls):
|
|
return reverse('autocomplete-lookup', args=[cls.name()])
|
|
|
|
def get_query(self, request, term):
|
|
return []
|
|
|
|
def get_item_label(self, item):
|
|
return smart_unicode(item)
|
|
|
|
def get_item_id(self, item):
|
|
return smart_unicode(item)
|
|
|
|
def get_item_value(self, item):
|
|
return smart_unicode(item)
|
|
|
|
def get_item(self, value):
|
|
return value
|
|
|
|
def create_item(self, value):
|
|
raise NotImplemented()
|
|
|
|
def format_item(self, item):
|
|
return {
|
|
'id': self.get_item_id(item),
|
|
'value': self.get_item_value(item),
|
|
'label': self.get_item_label(item)
|
|
}
|
|
|
|
def results(self, request):
|
|
term = request.GET.get('term', '')
|
|
raw_data = self.get_query(request, term)
|
|
data = []
|
|
for item in raw_data:
|
|
data.append(self.format_item(item))
|
|
content = json.dumps(data, cls=DjangoJSONEncoder, ensure_ascii=False)
|
|
return HttpResponse(content, content_type='application/json')
|
|
|
|
|
|
class LookupAlreadyRegistered(Exception):
|
|
pass
|
|
|
|
|
|
class LookupNotRegistered(Exception):
|
|
pass
|
|
|
|
|
|
class LookupInvalid(Exception):
|
|
pass
|
|
|
|
|
|
class LookupRegistry(object):
|
|
|
|
def __init__(self):
|
|
self._registry = {}
|
|
|
|
def validate(self, lookup):
|
|
if not issubclass(lookup, LookupBase):
|
|
raise LookupInvalid(u'Registered lookups must inherit from the \
|
|
LookupBase class')
|
|
|
|
def register(self, lookup):
|
|
self.validate(lookup)
|
|
name = force_unicode(lookup.name())
|
|
if name in self._registry:
|
|
raise LookupAlreadyRegistered(u'The name %s is already registered'\
|
|
% name)
|
|
self._registry[name] = lookup
|
|
|
|
def unregister(self, lookup):
|
|
self.validate(lookup)
|
|
name = force_unicode(lookup.name())
|
|
if name not in self._registry:
|
|
raise LookupNotRegistered(u'The name %s is not registered' % name)
|
|
del self._registry[name]
|
|
|
|
def get(self, key):
|
|
return self._registry.get(key, None)
|
|
|
|
|
|
class ModelLookup(LookupBase):
|
|
model = None
|
|
filters = {}
|
|
search_field = ''
|
|
|
|
def get_query(self, request, term):
|
|
qs = self.get_queryset()
|
|
if term and self.search_field:
|
|
qs = qs.filter(**{self.search_field: term})
|
|
return qs
|
|
|
|
def get_queryset(self):
|
|
qs = self.model._default_manager.get_query_set()
|
|
if self.filters:
|
|
qs = qs.filter(**self.filters)
|
|
return qs
|
|
|
|
def get_item_id(self, item):
|
|
return item.pk
|
|
|
|
def get_item(self, value):
|
|
item = None
|
|
if value:
|
|
try:
|
|
item = self.get_queryset().filter(pk=value)[0]
|
|
except IndexError:
|
|
pass
|
|
return item
|
|
|
|
def create_item(self, value):
|
|
data = {}
|
|
if self.search_field:
|
|
field_name = re.sub(r'__\w+$', '', self.search_field)
|
|
if field_name:
|
|
data = {field_name: value}
|
|
return self.model(**data)
|