4

Alright, I'm at a loss with the Django Forms, as the documentation just doesn't seem to quite cover what I'm looking for. At least it seems to come to a screeching halt once you get past the most rudimentary of forms. I'm more than willing to take a link to good documentation, or a link to a good book that covers this topic, as an answer. Basically, this is how it breaks down, I have 3 models (quiz, questions, answers). I have 20 questions, with 4 potential answers (multi-choice), per quiz. The numbers can vary, but you get the point.

I need to create a form for these items, much like you'd expect in a multiple choice quiz. However, when I create the form by hand in the templates, rather than using django.forms, I get the following:

invalid literal for int() with base 10: 'test'

So I'm trying to mess with the django.forms, but I guess I'm just not grasping the idea of how to build a proper form out of those. Any help would be greatly appreciated, thanks.

For what it's worth here are the models:

class Quiz(models.Model):
    label = models.CharField(blank=True, max_length=400)
    slug = models.SlugField()

    def __unicode__(self):
        return self.label

class Question(models.Model):
    label = models.CharField(blank=True, max_length=400)
    quiz = models.ForeignKey(Quiz)

    def __unicode__(self):
        return self.label

class Answer(models.Model):
    label = models.CharField(blank=True, max_length=400)
    question = models.ForeignKey(Question)
    correct = models.BooleanField()

    def __unicode__(self):
        return self.label
f4nt
  • 2,661
  • 5
  • 31
  • 35
  • 1
    Bashing the existing docs (which are quite good as open source docs go), rather than clarifying which ones you've read (i.e. have you read about ModelForms? formsets?), really decreases the motivation to answer your question. – Carl Meyer Mar 07 '09 at 20:40
  • 1
    Also, it's helpful to name your question in a way that actually describes what it's about. – Carl Meyer Mar 07 '09 at 20:41
  • Carl, I read all the docs on the forms, yes, all of them. They're great if you're doing extremely basic stuff. Other subjects are covered *extremely* well, just not forms. Bashing was not intended. Also, couldn't think of a good name for the question. Sorry for apparently offending you. – f4nt Mar 08 '09 at 06:57
  • Thanks to all who answered below. All the below answers contributed to my solution in the end, and has taught me a lot. Thanks for all the help peeps! – f4nt Mar 08 '09 at 17:14

2 Answers2

6

Yeah I have to agree the documentation and examples are really lacking here. The is no out of the box solution for the case you are describing because it goes three layers deep: quiz->question->answer.

Django has model inline formsets which solve the problem for two layers deep. What you will need to do to generate the form you want is:

  1. Load up a quiz form (just a label text box from your model)
  2. Load a an question formset: QuestionFormSet(queryset=Question.objects.filter(quiz=quiz))
  3. For each question load up a answer formset in much the same way you load up the question formset
  4. Make sure you save everything in the right order: quiz->question->answer, since each lower level needs the foreign key of the item above it
Jason Christa
  • 12,150
  • 14
  • 58
  • 85
2

First, you create a ModelForm for a given Model. In this example I'm doing it for Quiz but you can rinse and repeat for your other models. For giggles, I'm making the "label" be a Select box with preset choices:

from django.models import BaseModel
from django import forms
from django.forms import ModelForm

CHOICES_LABEL = (
    ('label1', 'Label One'),
    ('label2', 'Label Two')

)

class Quiz(models.Model):
    label = models.CharField(blank=True, max_length=400)
    slug = models.SlugField()

    def __unicode__(self):
        return self.label

class QuizForm(ModelForm):
    # Change the 'label' widget to a select box.
    label = forms.CharField(widget=forms.Select(choices=CHOICES_LABEL))

    class Meta:
       # This tells django to get attributes from the Quiz model
       model=Quiz

Next, in your views.py you might have something like this:

from django.shortcuts import render_to_response
from forms import *
import my_quiz_model

def displayQuizForm(request, *args, **kwargs):
   if request.method == 'GET':
       # Create an empty Quiz object. 
       # Alternately you can run a query to edit an existing object.

       quiz = Quiz()
       form = QuizForm(instance=Quiz)
       # Render the template and pass the form object along to it.
       return render_to_response('form_template.html',{'form': form})

   elif request.method == 'POST' and request.POST.get('action') == 'Save':
       form = Quiz(request.POST, instance=account)
       form.save()
       return HttpResponseRedirect("http://example.com/myapp/confirmsave")

Finally your template would look like this:

<html>
  <title>My Quiz Form</title>
  <body>

  <form id="form" method="post" action=".">

   <ul>
    {{ form.as_ul }}
   </ul>

   <input type="submit" name="action" value="Save">
   <input type="submit" name="action" value="Cancel">
  </form>

  </body>
</html>
Luis
  • 106
  • 2
  • I get part of this. What I don't get is how to display the questions and choices as part of a quiz. This doesn't seem to cover that, unless I'm just misunderstanding. Won't this just display a quiz with preset choices? – f4nt Mar 07 '09 at 03:39
  • I think this site will help you figure things out: http://djangobook.com/en/1.0/chapter05/ and http://djangobook.com/en/1.0/chapter07/ – Luis Mar 07 '09 at 04:30