views:

509

answers:

3

I am making a system for a company which among other things must hold information about the satisfactory level about various things, I have made it work fine using a fixed model with fixed questions and answers, but I am sure that they will need to change or add questions.

So I want to make a system where users can make custom evaluation schemas that consists of custom questions defined by them. How do I go about making such a design?

Right now my model is this, but wrong:

RATING_CHOICES = ((0, u"Good"), (1, u"Bad"), (2, u"Dunno"),)

class EvaluationScheme(models.Model):
    title = models.CharField(max_length=200)

class Evaluation(models.Model):
    doctor = models.CharField(max_length=200)
    agency = models.CharField(max_length=200)
    scheme = models.ForeignKey(EvaluationScheme)

class EvaluationQuestion(models.Model):
    question = models.CharField(max_length=200)
    evaluation = models.ForeignKey(EvaluationScheme)

    def __unicode__(self):
        return self.question

class EvaluationAnswer(models.Model):
    evaluation = models.ForeignKey(Evaluation)
    question = models.ForeignKey(EvaluationQuestion)
    answer = models.SmallIntegerField(choices=RATING_CHOICES)

This is sort of what I want, except that the EvaluationScheme is useless, since you still have to chose all questions and answers yourself - it does not display a list of only the questions related to the schema of choice.

+2  A: 

Have you checked django-survey? It's pretty neat.

Arnaud
A: 

Not a django expert so you might wish to wait for a more experience person to answer but you could try something like:

EvaluationQuestions.objects.filter(evaluationscheme__title="myscheme").select_related()

Could also put the relationships the other way around, depends how you need to access the data.

class EvaluationScheme(models.Model):
    title = models.CharField(max_length=200)
    evaluations = models.ManyToMany(Evaluation)
    questions = models.ManyToMany(EvaluationQuestions)
+1  A: 

I think your models are fine. I used the Django admin to create an EvaluationScheme with EvaluationQuestions, then I created an Evaluation and I was able to answer its questions. Here's the code I used to go with your models:

# forms.py:
from django.forms.models import inlineformset_factory
import models

AnswerFormSet = inlineformset_factory(models.Evaluation, 
        models.EvaluationAnswer, exclude=('question',), 
        extra=0, can_delete=False)

# views.py
from django.http import HttpResponse
from django.shortcuts import render_to_response, get_object_or_404
import models, forms

def prepare_blank_answers(evaluation):
    for question in evaluation.scheme.evaluationquestion_set.all():
        answer = models.EvaluationAnswer(evaluation=evaluation,
                                         question=question)
        answer.save()

def answer_form(request, id):
    evaluation = get_object_or_404(models.Evaluation, id=id)
    if len(evaluation.evaluationanswer_set.all()) == 0:
        prepare_blank_answers(evaluation)
    if request.method == 'POST':
        formset = forms.AnswerFormSet(request.POST, instance=evaluation)
        if formset.is_valid():
            formset.save()
            return HttpResponse('Thank you!')
    else:
        formset = forms.AnswerFormSet(instance=evaluation)
    return render_to_response('answer_form.html',
            {'formset':formset, 'evaluation':evaluation})


# answer_form.html:
<html><head></head><body>
  Doctor: {{ evaluation.doctor }} <br>
  Agency: {{ evaluation.agency }}
  <form method="POST">
    {{ formset.management_form }}
    <table>
      {% for form in formset.forms %}
        <tr><th colspan="2">{{ form.instance.question }}</th></tr>
        {{ form }}
      {% endfor %}
    </table>
    <input type="submit">
  </form>
</body></html>
Thank you for your contribution - but the problem is when you add more than one EvaluationScheme - then you are able to answer all questions, not just the questions related to the created scheme.At least that is the problem I have when using the administration interface. But maybe I need to go do some AJAX on those forms.
John Magistr
If you use my code here you shouldn't have that problem. The key line in my code is "for question in evaluation.scheme.evaluationquestion_set.all()" which grabs only those questions related to the scheme for this evaluation. If your code doesn't have a line like that, you will have the problem you report.