Динамический FilteredSelectMultiple в django-admin - PullRequest
0 голосов
/ 23 ноября 2011

Я не знаю, возможно ли это вообще, в любом случае, у меня сейчас есть что-то вроде следующего:

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 из incidence для выбора доступны только machines, связанные с этим instalation. Я думаю, что-то, как это невозможно:

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

Любые идеи будут высоко оценены. Спасибо!

Ответы [ 2 ]

1 голос
/ 20 июня 2012

Я заметил, что виджет FilteredSelectMultiple уже кэшировал, преобразовал и изменил имя исходного виджета после загрузки страницы, поэтому изменение списка «option» тега «select» недостаточно.

Я пришелс этим решением:

  • обернуть список "select" внутри другого элемента (например, "div")
  • использовать данные, полученные из вызова ajax, для воссоздания исходного списка
  • вызовите «SelectFilter.init», чтобы перестроить виджет 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
  • Джанго 1.2.5
1 голос
/ 23 ноября 2011

Вы можете сделать это после , модель будет сохранена, и с ней будет использоваться instalation (хотя поиск будет instalation=self.instance.instalation).

Однако,это не очень хорошо для вас, потому что, если выбран другой instalation, список все равно останется для старого выбора, и, очевидно, вы не получите никакой помощи при первом создании объекта.

Какрезультат, единственный способ сделать это с AJAX.Вы создаете представление для получения выбранного instalation id и возвращаете ответ JSON, состоящий из machines, связанного с ним.Свяжите представление с вашим 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);
...