Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

generating form for a simple survey-app

I am writing an app for a simple survey.

For possible answers I need "Yes/Now", "1 out of 1 to 5", and a short text

In the admin it should be selectable, what kind of answer should be given.

My models:

from django.db import models
from django.contrib.contenttypes.models import ContentType

CHOICES=((1,'excactly true'),(2,'mostly true'),(3,'mostly untrue'),(4,'untrue'),(5,'I don\'t know '))
class Answer(models.Model):
    question = models.ForeignKey("Question")

class ChoiceAnswer(Answer):
    answer = models.IntegerField(max_length=1, choices=CHOICES)
    def __unicode__(self):
        return u'%s: %s'%(self.question, self.answer)

class TextAnswer(Answer):
    answer= models.CharField(max_length=255)
    def __unicode__(self):
        return u'%s: %s'%(self.question, self.answer)

class BooleanAnswer(Answer):
    answer= models.BooleanField(choices=((True,'yes'),(False,'no')))
    def __unicode__(self):
        return u'%s: %s'%(self.question, self.answer)

class Question(models.Model):
    question = models.CharField(max_length=255)
    answer_type = models.ForeignKey(ContentType)

    def __unicode__(self):
        return u'%s'%self.question

Is there a (hopefully: simple) way for generating the form by looping over all questions and creating the an answer form compatible to the question's answer_type?

And is it possible to filter contenttypes for answer_type = models.ForeignKey(ContentType) so that only the answertypes will be shown?

like image 392
vikingosegundo Avatar asked Jun 10 '09 20:06

vikingosegundo


1 Answers

As I discovered a solution myself I will answer my own question:

models.py:

CHOICES=((1,'exactly true'),(2,'mostly true'),(3,'mostly untrue'),(4,'untrue'),(5,'I don\'t know '))

class Answer(models.Model):
    question = models.ForeignKey("Question")

class ChoiceAnswer(Answer):
    answer = models.IntegerField(max_length=1, choices=CHOICES)
    def __unicode__(self):
        return u'%s: %s'%(self.question, self.answer)

class TextAnswer(Answer):
    answer= models.TextField()
    def __unicode__(self):
        return u'%s: %s'%(self.question, self.answer)

class BooleanAnswer(Answer):
    answer= models.BooleanField(choices=((True,'yes'),(False,'no')))
    def __unicode__(self):
        return u'%s: %s'%(self.question, self.answer)

class Question(models.Model):
    question = models.CharField(max_length=255)
    answer_type = models.ForeignKey(ContentType)

    def __unicode__(self):
        return u'%s'%self.question

forms.py:

class ChoiceAnswerForm(forms.ModelForm):
    class Meta:
        model = ChoiceAnswer
        exclude=("question",)
ChoiceAnswer.form = ChoiceAnswerForm

class BooleanAnswerForm(forms.ModelForm):
    class Meta:
        model = BooleanAnswer
        exclude=("question",)
BooleanAnswer.form= BooleanAnswerForm

class TextAnswerForm(forms.ModelForm):
    class Meta:
        model = TextAnswer
        exclude=("question",)
TextAnswer.form = TextAnswerForm

the view:

#needed for monkey-patching.
from survey.forms import BooleanAnswerForm, TextAnswerForm, ChoiceAnswerForm 

def index(request):
    questions = Question.objects.all() 
    if request.method == 'POST': # If the form has been submitted...
        print request.POST
        for q in questions :
            try:
                data ={ u'%s-answer'%q.id: request.POST[u'%s-answer'%q.id]}
            except:
                data = { u'%s-answer'%q.id: None}
            q.form = q.answer_type.model_class().form(prefix="%s"%q.id, data=data)    
    else:
        for q in questions :
            q.form = q.answer_type.model_class().form(prefix="%s"%q.id) 

    return render_to_response('survey.html', {
        'questions': questions,

    })  

and in the template:

{% block content %}

    <div class="survey">
        <form enctype="multipart/*" action="/" method="post">

        {% for question in questions %}
            <p>{{ question.question }}</p><ul>{{ question.form.as_ul }}</ul>
        {% endfor %}

    <div><input type="submit" value="submit" /></div>
</form>
</div>

{% endblock %}

The monkey-patching could be avoid by some sort of registering. But for now I am fine with this.

EDIT

the contentype-filtering can be done like

answer_type = models.ForeignKey(ContentType, 
              limit_choices_to = Q(name='text answer', app_label='survey')| \
                                 Q(name='boolean answer', app_label='survey')| \
                                 Q(name='choice answer', app_label='survey'))
like image 125
vikingosegundo Avatar answered Sep 29 '22 09:09

vikingosegundo