Django – две формы в одном view

Иногда возникает необходимость показать две формы на одной странице.
Мы приводим перевод очень полезной статьи на эту тему.

Как это работает? Идея очень проста. Нужно сделать одно view, которое рендерит обе формы. Более того, в этом view используется только метод GET, поэтому возможности сделать POST не будет. Но в этом главном view будет еще два view, которые отвечают за обработку POST запросов для обеих форм. Вот простая картинка, наглядно демонстрирующая суть идеи: Django - Две формы на одной странице

Переходим к коду. Вот первое view, ответственное за рендеринг форм:

class MainView(TemplateView):
    template_name = 'sample_forms/index.html'

    def get(self, request, *args, **kwargs):
        question_form = QuestionForm(self.request.GET or None)
        answer_form = AnswerForm(self.request.GET or None)
        context = self.get_context_data(**kwargs)
        context['answer_form'] = answer_form
        context['question_form'] = question_form
        return self.render_to_response(context)

Это просто TemplateView, ответвтсенная за запрос GET. Сначала я получаю форму question и форму answer. Затем я добавляю эти формы в контекст context dictionary делаю рендеринг в sample_forms/index.html.

В этом примере sample_forms/index.html выглядит так:

Question Form
{% csrf_token %} {{ question_form }} <input type="submit" value="Send Question" />
Answer Form
{% csrf_token %} {{ answer_form }} <input type="submit" value="Send Answer" />

Здесь обрабатываются два разных действия, поэтому POST обращается к двум разным URL: форма question к question_form/submit и форма answer к answer_form/submit.

View, обрабатывающие запросы POST для обеих форм выглядит так:

 
class QuestionFormView(FormView):
    form_class = QuestionForm
    template_name = 'sample_forms/index.html'
    success_url = '/'

    def post(self, request, *args, **kwargs):
        question_form = self.form_class(request.POST)
        answer_form = AnswerForm()
        if question_form.is_valid():
            question_form.save()
            return self.render_to_response(
                self.get_context_data(
                success=True
            )
        )
        else:
        return self.render_to_response(
        self.get_context_data(
                question_form=question_form,
   
        )

class AnswerFormView(FormView):
    form_class = AnswerForm
    template_name = 'sample_forms/index.html'
    success_url = '/'

    def post(self, request, *args, **kwargs):
        answer_form = self.form_class(request.POST)
        question_form = QuestionForm()
        if answer_form.is_valid():
            answer_form.save()
            return self.render_to_response(
                self.get_context_data(
                success=True
            )
        )
        else:
            return self.render_to_response(
            self.get_context_data(
                    answer_form=answer_form,
                    question_form=question_form
            )
        )

Эти формы почти одинаковые, поэтому опишу одну из них: QuestionFormView.
В POST, я подтверждаю question_form запросом POST из пользовательского ввода. Сразу же после этого инициализируется пустая answer_form – так как если в первой форме будут ошибки я хочу отразить из во второй форме. Без этого будут обрабатываться только форма без ошибок. Следующие строки просты: проверяем, есть ли в форме ошибки: если нет, сохраняет форму и рендерим index.html в дополнительной переменной success. Зачем? Чтобы получить возможность на этой странице обработать информацию для пользователя:

{% if success %}
   Your request has been submitted
{% else %}
  # Forms here
{% endif %}

Если пользовательский ввод некорректен, обрабатываются обе формы: одна с ошибками, вторая – без.

Вот и все!

Поделитесь с друзьями:

Оставьте комментарий