如何使用Django表单创建过滤下拉列表?

时间:2013-10-25 09:42:50

标签: python django

我有这个型号:

class QuestionInstance(models.Model):
    questionsSet = models.ForeignKey(QuestionsSet)
    question     = models.ForeignKey(Question)
    parent       =  models.ForeignKey('self',null=True,blank=True)
    optional     = models.BooleanField(default=False)

我想创建一个下拉列表,用户可以选择一个QuestionInstance。 必须使用questionsSet过滤它。

我已经使用过像这样的模型进行过测试,但它无法正常工作:

(基于此How do I filter values in a Django form using ModelForm?

class FormQuestionSelect(ModelForm):
    instanceList = forms.ChoiceField(choices=[(questionInstance.id, questionInstance.question) for questionInstance in QuestionInstance.objects.all()])

    class Meta:
        model = QuestionInstance
        fields = ('instanceList', )
        widgets = {
            'instanceList': Select(attrs={'class': 'select'}),
        }

    def __init__(self, questionsSet=None, **kwargs):
        super(FormQuestionSelect, self).__init__(**kwargs)
        if questionsSet:
            #Tested many code here to filter, None of them worked :(
            #Is that possible to create instanceList there ?                        

我不确定使用模型是出于这种目的的好主意。

创建或更新模型实例时,modelform非常棒。 使用特定表单时,如本例所示,我在模板中使用自定义表单:

查看

questionInstanceList = QuestionInstance.objects.filter(questionsSet=questionsSet)

模板

<select name="questionInstanceSelect">
    {% for instance in questionInstanceList %}
        <option value="{{ instance.id }}">{{ instance.question.text }}</option>
    {% endfor %}
</select>

以这种方式处理它们:

instanceList = request.POST.get('questionInstanceSelect')

我很确定这是一种正确的方法。

2 个答案:

答案 0 :(得分:1)

您可以在表单__init__或视图中更改表单实例化后更改ModelChoiceField的查询集。但这不会解决客户端问题。当有人更改QuestionSet Question时,selectbox将保持不变

要更新查询集,只需更新表单字段的一个

form.fields['parent'].queryset = (QuestionInstance.objects
                                           .filter(questionsSet=questionsSet))

或如果您更改表单__init__

self.fields['parent'].queryset = (QuestionInstance.objects
                                           .filter(questionsSet=questionsSet))

但是应该记住,如果在客户端更改questionsSet,父列表将保持不变。

您是否考虑添加客户端代码更新父选择列表

让我解释一下。

你有模特

class QuestionInstance(models.Model):
    questionsSet = models.ForeignKey(QuestionsSet)
    question     = models.ForeignKey(Question)
    parent       =  models.ForeignKey('self',null=True,blank=True)
    optional     = models.BooleanField(default=False)

此处父字段链接到self(相同型号)。

让我们使用“此模型的模型表单”

class FormQuestionSelect(ModelForm):
    class Meta:
        model = QuestionInstance

ModelForm将为每个具有相同名称的模型字段创建字段 然后在创建完成后,我们更新ModelChoiceField(为ForeignKey创建)queryset

答案 1 :(得分:0)

如果您希望您的字段是动态的,则需要使用jQuery和ajax来实现此功能。我已经给出了在django admin中使用的代码。如果要在自定义页面中使用它,可以稍微调整一下。但这两个概念都是一样的。

question_set_change.js

(function($){   
    $(function(){
        $(document).ready(function() {
            $('#id_questionsSet').bind('change', question_set_change);            
            $('#id_question > option').show();
            if ($('#id_questionsSet').val() != '') {
                var question_set_id = $('#id_questionsSet').val();
                $.ajax({
                "type"      : "GET",
              "url"         : "/product_change/?question_set_id="+question_set_id,
                "dataType"  : "json",
              "cache"       : false,
                "success"   : function(json) {
                    $('#id_question >option').remove();
                    for(var j = 0; j < json.length; j++){
                        $('#id_question').append($('<option></option>').val(json[j][0]).html(json[j][1]));
                    }
                }           
            });
            }
        });
    });  
})(django.jQuery);

// based on the questionsSet, questions will be loaded

var $ = django.jQuery.noConflict();

function question_set_change()
{
    var question_set_id = $('#id_questionsSet').val();
    $.ajax({
    "type"      : "GET",
  "url"         : "/product_change/?question_set_id="+question_set_id,
    "dataType"  : "json",
  "cache"       : false,
    "success"   : function(json) {
        $('#id_question > option').remove();
        for(var j = 0; j < json.length; j++){
            $('#id_question').append($('<option></option>').val(json[j][0]).html(json[j][1]));
        }
    }           
})(jQuery);
}

在views.py中包含以下内容:

import simplejson
from django.shortcuts import HttpResponse

from app.models import Question

def question_choices(request): 
    question_list = []
    question_set_id = request.GET.get('question_set_id')
    questions       = Question.objects.filter(question_set = question_set_id)    
    [question_list.append((each_question.pk,each_question.name)) for each_question in questions]
    json = simplejson.dumps(question_list)
    return HttpResponse(json, mimetype='application/javascript')

在urls.py中:

from app.views import question_choices

urlpatterns = patterns(
    (r'^question_set_change/', question_choices),
)

在admin.py中,您要根据question_set加载问题:

class Media:
    js = ['/path/to/question_set_change.js',]