12

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.

John Magistr
  • 872
  • 3
  • 9
  • 22

4 Answers4

5

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>
krubo
  • 5,969
  • 4
  • 37
  • 46
  • 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 Jun 30 '09 at 10:15
  • 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. – krubo May 01 '10 at 12:19
4

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

Arnaud
  • 1,785
  • 18
  • 22
3

Django-crowdsourcing is a fork of django-survey that is actively maintained as of 2012 and targets Django 1.2+.

Bayard Randel
  • 9,930
  • 3
  • 42
  • 46
1

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)
PhoebeB
  • 8,434
  • 8
  • 57
  • 76