Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using muliple forms in the same view

Tags:

python

django

I am trying to learn django framework with few sample applications. Currently, I am working on a feedback/survey application. It uses the following models:

class Survey(models.Model):
    title = models.CharField(_(max_length=255)
    slug = models.SlugField(_(max_length=255, unique=True)
    description= models.TextField(blank=True)


class Question(models.Model):
    survey = models.ForeignKey(Survey, related_name='questions')
    question = models.TextField()

class Answer(models.Model):
    question = models.ForeignKey(Question, related_name='answers')
    answer = models.TextField()

Basically a survey will contain questions and their answers will be saved in the answer.

Now what I don't understand is how to create a form which will display all the questions of a survey when the view is called. I tried to create a form like this

class BaseAnswerForm(Form):
    answer = None
    def __init__(self, question,*args, **kwdargs):
        self.question = question
        #self.answer = None
        super(BaseAnswerForm, self).__init__(*args, **kwdargs)
        answer = self.fields['answer']
        answer.label = question.question

    def save(self, commit=True):
        ans = self.answer
        if ans is None:
            ans = Answer()
        ans.question = self.question
        ans.answer = self.cleaned_data['answer']
        if commit: ans.save()
        return ans

class TextAnswerForm(BaseAnswerForm):
    answer = CharField()

def forms_for_survey(survey, request):
    if request.POST:
        post = request.POST
    else:
        post = None
    return [TextAnswerForm(q,data=post)
            for q in survey.questions.all()]

view for this is like

def show_questions(request, slug):
    survey = get_object_or_404(Survey.objects, slug=slug)
    forms = forms_for_survey(survey, request)
    context = {
        'survey':survey,
        'forms':forms,
        }
    if (request.POST and all(form.is_valid() for form in forms)):
        for form in forms:
            form.save()
        return HttpResponseRedirect(reverse('show_surveys',))
    return render_to_response(
        'feedback/show_questions.html',
        context,
        context_instance = RequestContext(request)
        )

What this does is that, it generates the form as I want, but all the answers are saved from the last answer field. Please help me out, will this be easier using formsets, Can you tell me how it can implemented easier. Thanks

like image 214
dushyant88 Avatar asked Nov 30 '25 15:11

dushyant88


2 Answers

The reason is probably that the names of the form fields clash.

You could work around that issue, but did you already have a look at the Formsets Documentation?

A formset is a layer of abstraction to working with multiple forms on the same page.

like image 200
Daniel Hepper Avatar answered Dec 03 '25 03:12

Daniel Hepper


The prefix argument is there to prevent naming conflict issues when repeatedly using the same form (FormSets use it) or using forms which happen to have clashing field names - give each Form a unique prefix, which will be prepended to each generated field name. Using the Question's id would be ideal:

return [TextAnswerForm(q,data=post, prefix='q_%s' % q.pk)
        for q in survey.questions.all()]
like image 32
Jonny Buchanan Avatar answered Dec 03 '25 03:12

Jonny Buchanan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!