Skip to content
Open
76 changes: 51 additions & 25 deletions autocomplete/admin.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import string, operator
from django import forms
from django.conf import settings
from django.conf.urls.defaults import *
try:
from django.conf.urls.defaults import *
except ImportError:
from django.conf.urls import *
from django.contrib import admin
from django.contrib.admin.widgets import ForeignKeyRawIdWidget
from django.db import models
Expand All @@ -10,7 +13,11 @@
from django.template.loader import render_to_string
from django.utils.encoding import smart_str
from django.utils.safestring import mark_safe
from django.utils.text import get_text_list, truncate_words
from django.utils.text import get_text_list
try:
from django.utils.text import truncate_words
except ImportError:
from django.template.defaultfilters import truncatewords as truncate_words
from django.utils.translation import ugettext as _


Expand All @@ -28,23 +35,23 @@
class BaseAutocompleteWidget(ForeignKeyRawIdWidget):
widget_template = None
search_path = '../foreignkey_autocomplete/'

class Media:
css = css_dict
js = js_tuple
abstract = True

def label_for_value(self, value):
key = self.rel.get_related_field().name
obj = self.rel.to._default_manager.get(**{key: value})
return truncate_words(obj, 14)


class ForeignKeySearchWidget(BaseAutocompleteWidget):
def __init__(self, rel, search_fields, attrs=None):
self.search_fields = search_fields
super(ForeignKeySearchWidget, self).__init__(rel, attrs)

def render(self, name, value, attrs=None):
if attrs is None:
attrs = {}
Expand Down Expand Up @@ -87,7 +94,7 @@ class NoLookupsForeignKeySearchWidget(BaseAutocompleteWidget):
def __init__(self, rel, search_fields, attrs=None):
self.search_fields = search_fields
super(NoLookupsForeignKeySearchWidget, self).__init__(rel, attrs)

def render(self, name, value, attrs=None):
if attrs is None:
attrs = {}
Expand Down Expand Up @@ -130,7 +137,7 @@ class InlineForeignKeySearchWidget(BaseAutocompleteWidget):
def __init__(self, rel, search_fields, attrs=None):
self.search_fields = search_fields
super(InlineForeignKeySearchWidget, self).__init__(rel, attrs)

def render(self, name, value, attrs=None):
if attrs is None:
attrs = {}
Expand Down Expand Up @@ -173,19 +180,23 @@ class BaseAutocompleteAdminMixin(object):
related_search_fields = {}
related_string_functions = {}
related_search_filters = {}

class Meta:
abstract = True


def can_autocomplete(self, db_field):
return (isinstance(db_field, models.ForeignKey) and
db_field.name in self.related_search_fields)

def foreignkey_autocomplete(self, request):

def _restrict_queryset(queryset, search_fields):
for bit in search_fields.split(','):
if bit[0] == '#':
key, val = bit[1:].split('=')
queryset = queryset.filter(**{key: val})
return queryset

query = request.GET.get('q', None)
app_label = request.GET.get('app_label', None)
model_name = request.GET.get('model_name', None)
Expand All @@ -205,7 +216,7 @@ def construct_search(field_name):
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 = ''
Expand All @@ -218,7 +229,7 @@ def construct_search(field_name):
or_queries.append(
models.Q(**{construct_search(smart_str(field_name)): smart_str(bit)}))
other_qs = QuerySet(model)
other_qs.dup_select_related(queryset)
other_qs.query.select_related = queryset.query.select_related
other_qs = other_qs.filter(reduce(operator.or_, or_queries))
queryset = queryset & other_qs
queryset = _restrict_queryset(queryset, search_fields)
Expand All @@ -233,7 +244,7 @@ def construct_search(field_name):
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:
Expand All @@ -243,20 +254,19 @@ def get_help_text(self, field_name, model_name):
}
return _('Use the left field to do %(model_name)s lookups in the fields %(field_list)s.') % help_kwargs
return ''


class ForeignKeyAutocompleteAdmin(BaseAutocompleteAdminMixin, admin.ModelAdmin):
def formfield_for_dbfield(self, db_field, **kwargs):
if (isinstance(db_field, models.ForeignKey) and
db_field.name in self.related_search_fields):
if self.can_autocomplete(db_field):
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'] = ForeignKeySearchWidget(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)

def get_urls(self):
urls = super(ForeignKeyAutocompleteAdmin, self).get_urls()
search_url = patterns('',
Expand All @@ -266,16 +276,15 @@ def get_urls(self):

class NoLookupsForeignKeyAutocompleteAdmin(BaseAutocompleteAdminMixin, admin.ModelAdmin):
def formfield_for_dbfield(self, db_field, **kwargs):
if (isinstance(db_field, models.ForeignKey) and
db_field.name in self.related_search_fields):
if self.can_autocomplete(db_field):
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'] = NoLookupsForeignKeySearchWidget(db_field.rel, self.related_search_fields[db_field.name])
# kwargs['help_text'] = help_text
return super(NoLookupsForeignKeyAutocompleteAdmin, self).formfield_for_dbfield(db_field, **kwargs)

def get_urls(self):
urls = super(NoLookupsForeignKeyAutocompleteAdmin, self).get_urls()
search_url = patterns('',
Expand All @@ -285,19 +294,36 @@ def get_urls(self):

class InlineAutocompleteAdmin(BaseAutocompleteAdminMixin, admin.TabularInline):
def formfield_for_dbfield(self, db_field, **kwargs):
if (isinstance(db_field, models.ForeignKey) and
db_field.name in self.related_search_fields):
if self.can_autocomplete(db_field):
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'] = InlineForeignKeySearchWidget(db_field.rel, self.related_search_fields[db_field.name])
# kwargs['help_text'] = help_text
return super(InlineAutocompleteAdmin, self).formfield_for_dbfield(db_field, **kwargs)

def get_urls(self):
urls = super(InlineAutocompleteAdmin, self).get_urls()
search_url = patterns('',
(r'^foreignkey_autocomplete/$', self.admin_site.admin_view(self.foreignkey_autocomplete))
)
return search_url + urls

class InlineAutocompleteAdminStackedInline(BaseAutocompleteAdminMixin, admin.StackedInline):
def formfield_for_dbfield(self, db_field, **kwargs):
if self.can_autocomplete(db_field):
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'] = InlineForeignKeySearchWidget(db_field.rel, self.related_search_fields[db_field.name])
# kwargs['help_text'] = help_text
return super(InlineAutocompleteAdminStackedInline, self).formfield_for_dbfield(db_field, **kwargs)

def get_urls(self):
urls = super(InlineAutocompleteAdminStackedInline, self).get_urls()
search_url = patterns('',
(r'^foreignkey_autocomplete/$', self.admin_site.admin_view(self.foreignkey_autocomplete))
)
return search_url + urls
40 changes: 20 additions & 20 deletions autocomplete/geoadmin.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,23 @@
class BaseAutocompleteWidget(ForeignKeyRawIdWidget):
widget_template = None
search_path = '../foreignkey_autocomplete/'

class Media:
css = css_dict
js = js_tuple
abstract = True

def label_for_value(self, value):
key = self.rel.get_related_field().name
obj = self.rel.to._default_manager.get(**{key: value})
return truncate_words(obj, 14)


class ForeignKeySearchWidget(BaseAutocompleteWidget):
def __init__(self, rel, search_fields, attrs=None):
self.search_fields = search_fields
super(ForeignKeySearchWidget, self).__init__(rel, attrs)

def render(self, name, value, attrs=None):
if attrs is None:
attrs = {}
Expand Down Expand Up @@ -87,7 +87,7 @@ class NoLookupsForeignKeySearchWidget(BaseAutocompleteWidget):
def __init__(self, rel, search_fields, attrs=None):
self.search_fields = search_fields
super(NoLookupsForeignKeySearchWidget, self).__init__(rel, attrs)

def render(self, name, value, attrs=None):
if attrs is None:
attrs = {}
Expand Down Expand Up @@ -130,7 +130,7 @@ class InlineForeignKeySearchWidget(BaseAutocompleteWidget):
def __init__(self, rel, search_fields, attrs=None):
self.search_fields = search_fields
super(InlineForeignKeySearchWidget, self).__init__(rel, attrs)

def render(self, name, value, attrs=None):
if attrs is None:
attrs = {}
Expand Down Expand Up @@ -173,19 +173,19 @@ class BaseAutocompleteAdminMixin(object):
related_search_fields = {}
related_string_functions = {}
related_search_filters = {}

class Meta:
abstract = True

def foreignkey_autocomplete(self, request):

def _restrict_queryset(queryset, search_fields):
for bit in search_fields.split(','):
if bit[0] == '#':
key, val = bit[1:].split('=')
queryset = queryset.filter(**{key: val})
return queryset

query = request.GET.get('q', None)
app_label = request.GET.get('app_label', None)
model_name = request.GET.get('model_name', None)
Expand All @@ -205,7 +205,7 @@ def construct_search(field_name):
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 = ''
Expand All @@ -218,7 +218,7 @@ def construct_search(field_name):
or_queries.append(
models.Q(**{construct_search(smart_str(field_name)): smart_str(bit)}))
other_qs = QuerySet(model)
other_qs.dup_select_related(queryset)
other_qs.query.select_related = queryset.query.select_related
other_qs = other_qs.filter(reduce(operator.or_, or_queries))
queryset = queryset & other_qs
queryset = _restrict_queryset(queryset, search_fields)
Expand All @@ -233,7 +233,7 @@ def construct_search(field_name):
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:
Expand All @@ -243,11 +243,11 @@ def get_help_text(self, field_name, model_name):
}
return _('Use the left field to do %(model_name)s lookups in the fields %(field_list)s.') % help_kwargs
return ''


class ForeignKeyAutocompleteAdmin(BaseAutocompleteAdminMixin, admin.GeoModelAdmin):
def formfield_for_dbfield(self, db_field, **kwargs):
if (isinstance(db_field, models.ForeignKey) and
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)
Expand All @@ -256,7 +256,7 @@ def formfield_for_dbfield(self, db_field, **kwargs):
kwargs['widget'] = ForeignKeySearchWidget(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)

def get_urls(self):
urls = super(ForeignKeyAutocompleteAdmin, self).get_urls()
search_url = patterns('',
Expand All @@ -266,7 +266,7 @@ def get_urls(self):

class NoLookupsForeignKeyAutocompleteAdmin(BaseAutocompleteAdminMixin, admin.GeoModelAdmin):
def formfield_for_dbfield(self, db_field, **kwargs):
if (isinstance(db_field, models.ForeignKey) and
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)
Expand All @@ -275,7 +275,7 @@ def formfield_for_dbfield(self, db_field, **kwargs):
kwargs['widget'] = NoLookupsForeignKeySearchWidget(db_field.rel, self.related_search_fields[db_field.name])
# kwargs['help_text'] = help_text
return super(NoLookupsForeignKeyAutocompleteAdmin, self).formfield_for_dbfield(db_field, **kwargs)

def get_urls(self):
urls = super(NoLookupsForeignKeyAutocompleteAdmin, self).get_urls()
search_url = patterns('',
Expand All @@ -285,7 +285,7 @@ def get_urls(self):

class InlineAutocompleteAdmin(BaseAutocompleteAdminMixin, admin.TabularInline):
def formfield_for_dbfield(self, db_field, **kwargs):
if (isinstance(db_field, models.ForeignKey) and
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)
Expand All @@ -294,7 +294,7 @@ def formfield_for_dbfield(self, db_field, **kwargs):
kwargs['widget'] = InlineForeignKeySearchWidget(db_field.rel, self.related_search_fields[db_field.name])
# kwargs['help_text'] = help_text
return super(InlineAutocompleteAdmin, self).formfield_for_dbfield(db_field, **kwargs)

def get_urls(self):
urls = super(InlineAutocompleteAdmin, self).get_urls()
search_url = patterns('',
Expand Down
11 changes: 1 addition & 10 deletions autocomplete/static/js/jquery.bgiframe.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{% load i18n %}
{% load extrafilters %}
<input type="text" id="lookup_{{ name }}" value="{{ label }}" style="display:none;" />
<a href="{{ related_url }}{{ url }}" class="related-lookup" id="lookup_id_{{ name }}" onclick="return showRelatedObjectLookupPopup(this);">
<img src="{{ admin_media_prefix }}img/admin/selector-search.gif" width="16" height="16" alt="{% trans "Lookup" %}" />
Expand Down