Иногда возникает необходимость показать две формы на одной странице.
Мы приводим перевод очень полезной статьи на эту тему.
Как это работает? Идея очень проста. Нужно сделать одно view, которое рендерит обе формы. Более того, в этом view используется только метод GET, поэтому возможности сделать POST не будет. Но в этом главном view будет еще два view, которые отвечают за обработку POST запросов для обеих форм. Вот простая картинка, наглядно демонстрирующая суть идеи:
Переходим к коду. Вот первое 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 FormAnswer Form
Здесь обрабатываются два разных действия, поэтому 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 %}
Если пользовательский ввод некорректен, обрабатываются обе формы: одна с ошибками, вторая – без.
Вот и все!