2011-11-23 94 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