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?
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.
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'))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With