--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/lib/django_extensions/admin/__init__.py Wed Jan 20 12:37:40 2010 +0100
@@ -0,0 +1,125 @@
+#
+# Autocomplete feature for admin panel
+#
+# Most of the code has been written by Jannis Leidel and was updated a bit
+# for django_extensions.
+# http://jannisleidel.com/2008/11/autocomplete-form-widget-foreignkey-model-fields/
+#
+# to_string_function, Satchmo adaptation and some comments added by emes
+# (Michal Salaban)
+#
+import operator
+from django.http import HttpResponse, HttpResponseNotFound
+from django.contrib import admin
+from django.db import models
+from django.db.models.query import QuerySet
+from django.utils.encoding import smart_str
+from django.utils.translation import ugettext as _
+from django.utils.text import get_text_list
+
+from django_extensions.admin.widgets import ForeignKeySearchInput
+
+class ForeignKeyAutocompleteAdmin(admin.ModelAdmin):
+ """Admin class for models using the autocomplete feature.
+
+ There are two additional fields:
+ - related_search_fields: defines fields of managed model that
+ have to be represented by autocomplete input, together with
+ a list of target model fields that are searched for
+ input string, e.g.:
+
+ related_search_fields = {
+ 'author': ('first_name', 'email'),
+ }
+
+ - related_string_functions: contains optional functions which
+ take target model instance as only argument and return string
+ representation. By default __unicode__() method of target
+ object is used.
+ """
+
+ related_search_fields = {}
+ related_string_functions = {}
+
+ def __call__(self, request, url):
+ if url is None:
+ pass
+ elif url == 'foreignkey_autocomplete':
+ return self.foreignkey_autocomplete(request)
+ return super(ForeignKeyAutocompleteAdmin, self).__call__(request, url)
+
+ def foreignkey_autocomplete(self, request):
+ """
+ Searches in the fields of the given related model and returns the
+ result as a simple string to be used by the jQuery Autocomplete plugin
+ """
+ query = request.GET.get('q', None)
+ app_label = request.GET.get('app_label', None)
+ model_name = request.GET.get('model_name', None)
+ search_fields = request.GET.get('search_fields', None)
+ object_pk = request.GET.get('object_pk', None)
+ try:
+ to_string_function = self.related_string_functions[model_name]
+ except KeyError:
+ to_string_function = lambda x: x.__unicode__()
+ if search_fields and app_label and model_name and (query or object_pk):
+ def construct_search(field_name):
+ # use different lookup methods depending on the notation
+ if field_name.startswith('^'):
+ return "%s__istartswith" % field_name[1:]
+ elif field_name.startswith('='):
+ return "%s__iexact" % field_name[1:]
+ elif field_name.startswith('@'):
+ return "%s__search" % field_name[1:]
+ else:
+ return "%s__icontains" % field_name
+ model = models.get_model(app_label, model_name)
+ queryset = model._default_manager.all()
+ data = ''
+ if query:
+ for bit in query.split():
+ or_queries = [models.Q(**{construct_search(
+ smart_str(field_name)): smart_str(bit)})
+ for field_name in search_fields.split(',')]
+ other_qs = QuerySet(model)
+ other_qs.dup_select_related(queryset)
+ other_qs = other_qs.filter(reduce(operator.or_, or_queries))
+ queryset = queryset & other_qs
+ data = ''.join([u'%s|%s\n' % (
+ to_string_function(f), f.pk) for f in queryset])
+ elif object_pk:
+ try:
+ obj = queryset.get(pk=object_pk)
+ except:
+ pass
+ else:
+ data = to_string_function(obj)
+ return HttpResponse(data)
+ return HttpResponseNotFound()
+
+ def get_help_text(self, field_name, model_name):
+ searchable_fields = self.related_search_fields.get(field_name, None)
+ if searchable_fields:
+ help_kwargs = {
+ 'model_name': model_name,
+ 'field_list': get_text_list(searchable_fields, _('and')),
+ }
+ return _('Use the left field to do %(model_name)s lookups in the fields %(field_list)s.') % help_kwargs
+ return ''
+
+ def formfield_for_dbfield(self, db_field, **kwargs):
+ """
+ Overrides the default widget for Foreignkey fields if they are
+ specified in the related_search_fields class attribute.
+ """
+ if (isinstance(db_field, models.ForeignKey) and
+ db_field.name in self.related_search_fields):
+ model_name = db_field.rel.to._meta.object_name
+ help_text = self.get_help_text(db_field.name, model_name)
+ if kwargs.get('help_text'):
+ help_text = u'%s %s' % (kwargs['help_text'], help_text)
+ kwargs['widget'] = ForeignKeySearchInput(db_field.rel,
+ self.related_search_fields[db_field.name])
+ kwargs['help_text'] = help_text
+ return super(ForeignKeyAutocompleteAdmin,
+ self).formfield_for_dbfield(db_field, **kwargs)