I want to display ManyToManyField
s in admin just like filter_horizontal
does, but populate the options as the user types into the filter field. There a
I started from your code and I used a custom javascript to retrieve values from photologue Photo model; please note that I'm using grappelli and the Django url that get the json object is hardcoded; also the field in my model is called "photos":
# urls.py
url(r'^get_json_photos/(?P[\w-]+)/$', 'catalogo.views.get_json_photos', name='get_json_photos'),
# views.py
from photologue.models import Photo
from django.utils import simplejson as json
def get_json_photos(request, query):
photos = Photo.objects.filter(title__icontains=query)[:20]
p = [ {"name":photo.title, "id":photo.id} for photo in photos ]
response = json.dumps(p)
return HttpResponse(response, mimetype="application/json")
# admin.py
from django.conf import settings
from django.contrib.admin.widgets import FilteredSelectMultiple
class MyFilteredSelectMultiple(FilteredSelectMultiple):
class Media:
js = (settings.ADMIN_MEDIA_PREFIX + "js/core.js",
settings.ADMIN_MEDIA_PREFIX + "js/SelectBox.js",
settings.ADMIN_MEDIA_PREFIX + "js/SelectFilter2.js",
settings.MEDIA_URL + "js/ajax_photo_list.js")
class MyModelMultipleChoiceField(ModelMultipleChoiceField):
def clean(self, value):
return [val for val in value]
class GalleryForm(forms.ModelForm):
photos = MyModelMultipleChoiceField(queryset=Photo.objects.none(), required=False,
widget=MyFilteredSelectMultiple(verbose_name="photos", is_stacked=False))
def __init__(self, *args, **kwargs):
super(GalleryForm, self).__init__(*args, **kwargs)
try:
i = kwargs["instance"]
gallery = Gallery.objects.get(pk=i.pk)
qs = gallery.photos.all()
except:
qs = Photo.objects.none()
self.fields['photos'].queryset = qs
class Meta:
model = Gallery
widgets = {
'photos': MyFilteredSelectMultiple(verbose_name="photos", is_stacked=False)
}
class GalleryAdmin(admin.ModelAdmin):
list_display = ('title', 'date_added', 'photo_count', 'is_public')
list_filter = ['date_added', 'is_public']
date_hierarchy = 'date_added'
prepopulated_fields = {'title_slug': ('title',)}
filter_horizontal = ()
form = GalleryForm
# ajax_photo_list.js
(function($){
$("#id_photos_input").live("keyup", function(){
var querystring = $("#id_photos_input").val();
if (querystring) {
$.ajax ({
type: "GET",
url: "/get_json_photos/"+querystring+"/",
cache: false,
success: function(json) {
if (json) {
var list_from = $("#id_photos_from option").map(function() {
return parseInt($(this).val());
});
var list_to = $("#id_photos_to option").map(function() {
return parseInt($(this).val());
});
for (var pid in json) {
if ($.inArray(json[pid].id, list_from) == -1 && $.inArray(json[pid].id, list_to) == -1) {
$("#id_photos_from").prepend("");
}
}
SelectBox.init('id_photos_from');
SelectBox.init('id_photos_to');
}
}
});
}
})
}(django.jQuery));
I'm thinking to make it generic, since is not the first time that I have this problem,