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 are many options and loading them all at once takes a lot of time.
I found django-ajax-filtered-fields but it seems to me an overkill as it requires changes to model classes, when all I want to do is to replace every multiple select field in a form.
Writing a custom widget field that inherits from admin.widgets.FilteredSelectMultiple
seems to be the right way. So I am trying to roll my own widget:
class MultiSelectWidget(FilteredSelectMultiple):
class Media:
# here should be some js to load options dynamically
js = (
"some_js_to_load_ajax_options.js",
)
def render_options(self, choices, selected_choices):
# this initializes the multiple select without any options
choices = [c for c in self.choices if str(c[0]) in selected_choices]
self.choices = choices
return super(MultiSelectWidget,
self).render_options([], selected_choices)
class MyAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(MyAdminForm, self).__init__(*args, **kwargs)
self.fields['m2m_field'].widget = MultiSelectWidget('m2m_field', is_stacked=False)
class Meta:
model = MyModel
class MyAdmin(admin.ModelAdmin):
form = MyAdminForm
which renders correctly.
But I am not sure how to implement this some_js_to_load_ajax_options.js
ajax part. Should I write my own jQuery snippet or modify SelectFilter2
which comes with admin/media/js
? Anybody been there before?
edit:
Although not related to the core of the question, as I only want to override the field's widget, the shorter way is to use formfield_overrides
:
class MultiSelectWidget(FilteredSelectMultiple):
# as above
class MyAdmin(admin.ModelAdmin):
formfield_overrides = {
models.ManyToManyField: {'widget': MultiSelectWidget},
}
code
SelectBox.init('id_photos_from'); SelectBox.init('id_photos_to');code
– Transience