Skip to content

Commit 379fecb

Browse files
committed
[soc2009/admin-ui] Moving the autocomplete view to a more appropriate location under the ModelAdmin
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/admin-ui@11465 bcc190cf-cafb-0310-a4f2-bffc1f526a37
1 parent 3a99684 commit 379fecb

File tree

6 files changed

+54
-113
lines changed

6 files changed

+54
-113
lines changed

django/contrib/admin/options.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import operator
12
from django import forms, template
23
from django.forms.formsets import all_valid
34
from django.forms.models import modelform_factory, modelformset_factory, inlineformset_factory
@@ -9,6 +10,7 @@
910
from django.core.exceptions import PermissionDenied
1011
from django.db import models, transaction
1112
from django.db.models.fields import BLANK_CHOICE_DASH
13+
from django.db.models.query import QuerySet
1214
from django.http import Http404, HttpResponse, HttpResponseRedirect
1315
from django.shortcuts import get_object_or_404, render_to_response
1416
from django.utils.datastructures import SortedDict
@@ -19,7 +21,7 @@
1921
from django.utils.text import capfirst, get_text_list
2022
from django.utils.translation import ugettext as _
2123
from django.utils.translation import ungettext, ugettext_lazy
22-
from django.utils.encoding import force_unicode
24+
from django.utils.encoding import force_unicode, smart_str
2325
try:
2426
set
2527
except NameError:
@@ -242,6 +244,9 @@ def wrapper(*args, **kwargs):
242244
url(r'^add/$',
243245
wrap(self.add_view),
244246
name='%s_%s_add' % info),
247+
url(r'^autocomplete/(?P<field>[\w-]+)/$',
248+
wrap(self.autocomplete_view),
249+
name='%s_%s_autocomplete' % info),
245250
url(r'^(.+)/history/$',
246251
wrap(self.history_view),
247252
name='%s_%s_history' % info),
@@ -708,6 +713,42 @@ def response_action(self, request, queryset):
708713
else:
709714
return HttpResponseRedirect(".")
710715

716+
def autocomplete_view(self, request, field, extra_content=None):
717+
"""
718+
Used by the JQuery Autocomplete plugin to do searches on fields of the related model
719+
"""
720+
query = request.GET.get('q', None)
721+
722+
if field not in self.autocomplete_fields or query is None:
723+
raise Http404
724+
725+
related = getattr(self.model, field)
726+
rel_model = related.field.rel.to
727+
queryset = rel_model._default_manager.all()
728+
search_fields = self.autocomplete_fields[field]
729+
730+
def construct_search(field_name):
731+
# use different lookup methods depending on the notation
732+
if field_name.startswith('^'):
733+
return "%s__istartswith" % field_name[1:]
734+
elif field_name.startswith('='):
735+
return "%s__iexact" % field_name[1:]
736+
elif field_name.startswith('@'):
737+
return "%s__search" % field_name[1:]
738+
else:
739+
return "%s__icontains" % field_name
740+
741+
for bit in query.split():
742+
or_queries = [models.Q(**{construct_search(
743+
smart_str(field_name)): smart_str(bit)})
744+
for field_name in search_fields]
745+
other_qs = QuerySet(rel_model)
746+
other_qs.dup_select_related(queryset)
747+
other_qs = other_qs.filter(reduce(operator.or_, or_queries))
748+
queryset = queryset & other_qs
749+
750+
return HttpResponse(''.join([u'%s|%s\n' % (unicode(f), f.pk) for f in queryset]))
751+
711752
def add_view(self, request, form_url='', extra_context=None):
712753
"The 'add' admin view for this model."
713754
model = self.model

django/contrib/admin/sites.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,6 @@ def wrapper(*args, **kwargs):
213213
url(r'^jsi18n/$',
214214
wrap(self.i18n_javascript, cacheable=True),
215215
name='jsi18n'),
216-
url(r'^foreignkey_autocomplete/$',
217-
'django.contrib.admin.views.autocomplete.foreignkey_autocomplete'),
218216
url(r'^r/(?P<content_type_id>\d+)/(?P<object_id>.+)/$',
219217
'django.views.defaults.shortcut'),
220218
url(r'^(?P<app_label>\w+)/$',

django/contrib/admin/templates/widget/foreignkey_searchinput.html

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,11 @@
1111
$('#id_{{ name }}').val('');
1212
$('#lookup_{{ name }}').val('');
1313
};
14-
function lookup(query) {
15-
$.get('{{ search_path }}', {
16-
'search_fields': '{{ search_fields }}',
17-
'app_label': '{{ app_label }}',
18-
'model_name': '{{ model_name }}',
19-
'object_pk': query
20-
}, function(data){
21-
$('#lookup_{{ name }}').val(data);
22-
{{ name }}_value = query;
23-
});
24-
};
25-
$('#id_{{ name }}').bind(($.browser.opera ? "keypress" : "keyup"), function(event) {
26-
if ($(this).val()) {
27-
if (event.keyCode == 27) {
28-
reset();
29-
} else {
30-
lookup($(this).val());
31-
};
32-
};
33-
});
34-
$('#lookup_{{ name }}').autocomplete('{{ search_path }}', {
35-
extraParams: {
36-
'search_fields': '{{ search_fields }}',
37-
'app_label': '{{ app_label }}',
38-
'model_name': '{{ model_name }}'
39-
}
40-
}).result(function(event, data, formatted) {
41-
if (data) {
42-
$('#id_{{ name }}').val(data[1]);
14+
15+
$('#lookup_{{ name }}').autocomplete('{{ search_path }}').result(
16+
function(event, data, formatted) {
17+
if (data) {
18+
$('#id_{{ name }}').val(data[1]);
4319
}
4420
}).keyup(function(event){
4521
if (event.keyCode == 27) {

django/contrib/admin/templates/widget/m2m_searchinput.html

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,7 @@
88
// Show lookup input
99
$("#lookup_{{ name }}").show();
1010

11-
function lookup(query) {
12-
$.get('{{ search_path }}', {
13-
'search_fields': '{{ search_fields }}',
14-
'app_label': '{{ app_label }}',
15-
'model_name': '{{ model_name }}',
16-
'object_pk': query
17-
}, function(data){
18-
$('#lookup_{{ name }}').val(data);
19-
});
20-
};
2111
$('#lookup_{{ name }}').autocomplete('{{ search_path }}', {
22-
extraParams: {
23-
'search_fields': '{{ search_fields }}',
24-
'app_label': '{{ app_label }}',
25-
'model_name': '{{ model_name }}'
26-
},
2712
multiple: true,
2813
mustMatch: true
2914
}).result(function(event, data, formatted) {

django/contrib/admin/views/autocomplete.py

Lines changed: 0 additions & 60 deletions
This file was deleted.

django/contrib/admin/widgets.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,6 @@ class ForeignKeySearchInput(ForeignKeyRawIdWidget):
158158
"""
159159
# Set in subclass to render the widget with a different template
160160
widget_template = 'widget/foreignkey_searchinput.html'
161-
# Set this to the path of the search view
162-
search_path = '../../../foreignkey_autocomplete/'
163161

164162
class Media:
165163
css = {
@@ -181,6 +179,9 @@ def __init__(self, rel, search_fields, attrs=None):
181179
self.search_fields = search_fields
182180
super(ForeignKeySearchInput, self).__init__(rel, attrs)
183181

182+
def get_search_path(self, name):
183+
return '../autocomplete/%s/' % name
184+
184185
def render(self, name, value, attrs=None):
185186
if attrs is None:
186187
attrs = {}
@@ -206,7 +207,7 @@ def render(self, name, value, attrs=None):
206207
'url': url,
207208
'related_url': related_url,
208209
'admin_media_prefix': settings.ADMIN_MEDIA_PREFIX,
209-
'search_path': self.search_path,
210+
'search_path': self.get_search_path(name),
210211
'search_fields': ','.join(self.search_fields),
211212
'model_name': model_name,
212213
'app_label': app_label,
@@ -270,8 +271,6 @@ class ManyToManySearchInput(ManyToManyRawIdWidget):
270271
"""
271272
# Set in subclass to render the widget with a different template
272273
widget_template = 'widget/m2m_searchinput.html'
273-
# Set this to the path of the search view
274-
search_path = '../../../foreignkey_autocomplete/'
275274

276275
class Media:
277276
css = {
@@ -293,6 +292,8 @@ def label_for_value(self, value):
293292
objs = self.rel.to._default_manager.filter(**{key + '__in': value.split(',')})
294293
return ','.join([str(o) for o in objs])
295294

295+
def get_search_path(self, name):
296+
return '../autocomplete/%s/' % name
296297

297298
def render(self, name, value, attrs=None):
298299
if attrs is None:
@@ -323,7 +324,7 @@ def render(self, name, value, attrs=None):
323324
'url': url,
324325
'related_url': related_url,
325326
'admin_media_prefix': settings.ADMIN_MEDIA_PREFIX,
326-
'search_path': self.search_path,
327+
'search_path': self.get_search_path(name),
327328
'search_fields': ','.join(self.search_fields),
328329
'model_name': model_name,
329330
'app_label': app_label,

0 commit comments

Comments
 (0)