2011-11-23 96 views
0

我不知道这甚至有可能,任何方式,我现在有事,如下所示:动态FilteredSelectMultiple在Django管理员

class Incidence(models.Model): 
    ... 
    instalation = models.ForeignKey('Instalation') 
    machine = models.ManyToManyField('Machine') 
    ... 

class Machine(models.Model): 
    ... 
    instalation = models.ForeignKey('Instalation') 
    ... 

所以Machines属于instalationsincidences涉及machinesincidences,这个想法是将一个动态的FilteredSelectMultiple小部件在管理页面中选择与incidence相关的machines。管理员目前,有几分像:

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。这个想法是,当您选择incidenceinstalation时,只有与instalation相关的machines可供选择。我猜这是不可能的:

queryset=Machine.objects.filter(instalation=self.instalation).order_by('hostname'), 

任何想法将不胜感激。谢谢!

回答

1

你可以做到这一点模型已被保存,并有与之相关联的使用(虽然查找就instalation=self.instance.instalation)的instalation

但是,这并不会对你有什么好处,因为如果选择了不同的instalation,那么该列表仍然是旧选择的列表,并且显然在首次创建对象时没有任何帮助。

因此,实现这一目标的唯一方法就是使用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); 
+0

谢谢!无论如何,我感觉它并不那么容易,我会尝试它! – Daehin

1

我注意到FilteredSelectMultiple小部件已经被缓存,转换和加载页面后改变了原来的小部件的名称,所以改变“的“选项”列表选择“标签是不够的。

我想出了这个解决方案:

  • 包装“选择”列表中的其他元素(“格”为实例)从Ajax调用收到
  • 使用里面的数据来重新创建原始列表
  • 调用“SelectFilter。初始化”重新构建FilteredSelectMultiple插件

下面是我已经测试的代码:

$('#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"]] 

对于服务器请参阅克里斯普拉特的回答

注意:测试:

  • jQuery的1.7.2
  • 的Django 1.2.5