The use of mulphilic forms in one view

I am trying to learn the django structure with a few sample applications. I am currently working on a feedback / polling 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, the survey will contain questions, and their answers will be saved in the answer.

Now I do not understand how to create a form on which all survey questions will be displayed when the view is called. I tried to create such a form

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()]

the view for this is similar to

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 does this mean, it generates the form as I want, but all the responses are saved from the last response field. Please help me if it will be easier with the help of forms, could you tell me how it is easier to implement. Thanks

+3
source share
3 answers

prefix ( FormSets) , - Form prefix, . :

return [TextAnswerForm(q,data=post, prefix='q_%s' % q.pk)
        for q in survey.questions.all()]
+1

, , .

, ?

- .

+2

you cannot get from the request object how many forms were on the www client page.

It is allowed to use several forms in an html document, but the only difference is that the POST / GET data contains only the fields from the submitted form. So put all your input in one form and then the easiest solution is to write something like this in your template

<form action="your_viw" method="post">
    {% for q in questions %}
        {{q.question}}<input name="q_{{q.id}}" type="text" />
    {% endfor %}
</form>

and in your opinion

def show_questions(request, slug):
    survey = get_object_or_404(Survey.objects, slug=slug)
    context = {
        'survey':survey,
        'questions': survey.questions_set,
        }
    fields=[(int(name[2:]), val) for name, val in request.POST.items() if name.startswith('q_')]   # (question id, answer) list
    if fields:
         #validate fields
         # rest of work...
    return ...

Sorry if there is a misspelled word.

+1
source

Source: https://habr.com/ru/post/1786120/


All Articles