我不知道这是否可行,无论如何,我目前有以下内容:
class Incidence(models.Model):
...
instalation = models.ForeignKey('Instalation')
machine = models.ManyToManyField('Machine')
...
class Machine(models.Model):
...
instalation = models.ForeignKey('Instalation')
...
因此Machines
属于instalations
且incidences
与machines
和incidences
相关,其目的是设置动态FilteredSelectMultiple
小部件选择与管理页面中的machines
相关的incidence
。管理员目前是:
class IncidenceMachineForm(forms.ModelForm):
filtered_machine = ModelMultipleChoiceField(
queryset=Machine.objects.order_by('hostname'),
required=False, widget=FilteredSelectMultiple("filtered machine name", is_stacked=False)
)
class Meta:
model = Incidence
然后,modelAdmin
使用IncidenceMachineForm
形式。我们的想法是,当您选择instalation
的{{1}}时,只有与incidence
相关的machines
可供选择。我想这是不可能的事情:
instalation
任何想法都将受到高度赞赏。谢谢!
答案 0 :(得分:1)
你可以在保存模型后执行,并且有一个instalation
与之关联(尽管查找将是instalation=self.instance.instalation
)。
然而,这对你没有多大帮助,因为如果选择了不同的instalation
,那么列表仍然是旧选择的列表,显然你在第一次创建对象时没有任何帮助。 / p>
因此,实现这一目标的唯一方法是使用AJAX。您创建一个视图以接收选定的instalation
ID,并返回由与之关联的machines
组成的JSON响应。将视图绑定到您的urlconf,然后使用AJAX点击它并根据结果更新选择框。
from django.http import Http404, HttpResponse
from django.shortcuts import get_object_or_404
from django.utils import simplejson
def ajax_admin_get_machines_for_instalation(request):
instalation_id = request.GET.get('instalation_id')
if instalation_id is None:
# instalation_id wasn't provided so return all machines
machines_qs = Machine.objects.all()
else:
instalation = get_object_or_404(Instalation, pk=instalation_id)
machines_qs = Machine.objects.filter(instalation=instalation)
# 'name' is the field you want to use for the display value
machines = machines_qs.values('pk', 'name')
return HttpResponse(simplejson.dumps(machines), mimetype='application/json')
然后JS:
(function($){
$(document).ready(function(){
function update_machine_options(){
var selected = $('#id_instalation').val();
if (selected) {
$.getJSON('/url/for/ajax/view/', {
instalation_id: selected
}, function(data, jqXHR){
var options = [];
for (k in data) {
options.append('<option value="'+data[k].pk+'">'+data[k].name+'</option>');
}
$('#id_machine').html(options.join(''));
});
}
}
update_machine_options();
$('#id_instalation').change(function(){
update_machine_options();
});
});
})(django.jQuery);
答案 1 :(得分:1)
我注意到FilteredSelectMultiple小部件在页面加载后已经缓存,转换并更改了原始小部件的名称,因此更改了&#34;选项&#34; &#34;选择&#34;标签是不够的。
我提出了这个解决方案:
以下是我测试的代码:
$('#id_instalation').change(function() {
var selected = $('#id_instalation').val();
if(selected) {
$.ajax({
url: '/url/to/get/machines/' + selected,
success: function(list) {
var options = [];
options.push('<select multiple="multiple" class="selectfilter" name="machine" id="id_machine">');
for(i in list){
options.push('<option value="' + list[i][0] + '">' +
list[i][1] + '</option>');
}
options.push('</select>');
$('#machine_wrapper').html(options.join(''));
// Change title of widget
var title = $('#id_instalation option:selected"').text().toLowerCase();
SelectFilter.init("id_machine", title, 0, "/path/to/django/media/");
},
error: function() {
alert('Server error');
},
});
}
}
这是从ajax调用返回的数据样本:
[[1, "Machine 1"], [2, "Machine 2"], [3, "Machine 3"]]
对于服务器端实现,请参阅Chris Pratt的回答
注意:测试时:
答案 2 :(得分:0)
from django.contrib.admin.widgets import FilteredSelectMultiple
@admin.register(YourModel)
class YourModelAdmin(admin.ModelAdmin):
def formfield_for_manytomany(self, db_field, request, **kwargs):
kwargs['widget'] = FilteredSelectMultiple(
db_field.verbose_name,
False,
)
return super().formfield_for_manytomany(db_field, request, **kwargs)
快速,不需要覆盖ModelForm等。 影响所有m2m字段。