4

I've got this model :

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)

I'd like to create a dropdown, which user could choose one QuestionInstance. It has to be filtered with questionsSet.

I've tested using a modelform like this, but it's not working :

(based on this 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 ?                        

I'm not sure using a modelform is a good idea for this kind of purpose.

A modelform is great when create or update a model instance. When using specific forms, like in this case, I'm using a custom form in template :

View

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

Template

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

and process them this way :

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

I'm quite sure there's a proper way.

5
  • Maybe this question can help you out: how-to-get-interdependent-dropdowns Commented Oct 25, 2013 at 9:49
  • how should your form behave after changing selection of QuestionSet by user without form submit? Commented Oct 25, 2013 at 9:52
  • You want the Question foreignkey to be filtered based on selected QuestionSet. Am I correct? Commented Oct 25, 2013 at 10:15
  • @oleg I only want to display QuestionInstance list, filtrered by current QuestionSet (which is set from the view) Commented Oct 25, 2013 at 17:34
  • @arulmr thats correct Commented Oct 25, 2013 at 17:34

2 Answers 2

1

You can change queryset of ModelChoiceField after form instantiation either in form __init__ or in view. but this wouldn't solve issue on client side. When someone change QuestionSet Question selectbox will remain the same

To update queryset just update form field's one

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

or if You change form __init__

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

But One should remember that if questionsSet is changed on client side parent list will remain the same.

Would You consider to add client side code updating parent's choice list

Let me explain a bit.

You have model

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)

Here parent field link to self(the same model).

Let us use `Model form for this model

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

ModelForm will create fields for each model field with the same name then after Its creation we update ModelChoiceField (created for ForeignKey) queryset

Sign up to request clarification or add additional context in comments.

3 Comments

I'm not sure to understand correctly. But I don't need to refresh list after it has been instanciated.
does not work. Why are you using "parent" field ? the field created by the form is named questionInstance
please see my explanation
0

If you want your field to be dynamic, you need to use jQuery and ajax for this functionality. I have given code for use in django admin. You can tweak it a bit, if you want to use it in custom pages. But the concept remains same for both.

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);
}

Include the following in 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')

In urls.py:

from app.views import question_choices

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

In admin.py where you want to load question based on question_set:

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

1 Comment

My dropdown is generated by the view. I don't need Ajax right now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.