我正在尝试在任意页面上呈现Django联系表单。我正在使用请求上下文处理器和模板包含。这允许我在任何我想要的地方显示表单。然后我有一个特殊的URL接受POST请求(在GET上,我只是重定向它们)。如果表单有效,我会发送电子邮件,然后重定向到成功页面。在表单无效的情况下,我知道传递带有错误的表单,但是......我不知道要指定哪个模板,因为表单是一个包含,父模板可以在任何地方。
在Django视图中获取内容的唯一方法是来自请求。我可以通过更多的工作获得路径,可能是POST来自的原始视图,但这并不能让我成为模板。
# urls.py
url(r'^services/$', 'website.views.services', name='services'),
url(r'^services/contact/$', 'website.views.services_contact', name='services_contact'),
url(r'^services/contact/done/$', 'website.views.services_contact_done', name='services_contact_done')
# views.py
class ServicesView(TemplateView):
template_name = 'services/services.html'
services = ServicesView.as_view()
class ServicesContactView(View):
def get(self, request, *args, **kwargs):
return redirect('services')
def post(self, request, *args, **kwargs):
form = ContactForm(request.POST)
if form.is_valid():
form.send_email()
return redirect('services_contact_done')
else:
return render(request, ????, {'contact_form': form})
services_contact = ServicesContactView.as_view()
# contact.html
<h2>Contact me</h2>
<p>Enter your email to receive your questionnaire</p>
<form action="{% url 'services_contact' %}" method="post">
{% csrf_token %}
{% if contact_form.non_field_errors %}
{{ contact_form.non_field_errors }}
{% endif %}
{{ contact_form.as_p }}
<button type="submit" name="submit">Send questionnaire</button>
</form>
# home.html
{% extends "base.html" %}
{% block content %}
<h1>{{ site.name }}</h1>
{% include "services/contact.html" %}
{% endblock %}
典型的Django表单视图在表单上是无声的,因为它的场景大部分类似于未绑定的表单,所以最后只是渲染。由于模板包含,我的情况不同。
答案 0 :(得分:1)
您可以在每次渲染模板时设置会话变量,并在需要时使用它:
request.session['template']="nameOfTemplate"
return render(request, request.session.get('template', 'default.html'), {'contact_form': form})
我知道每次渲染模板时都需要编写一行代码,但这是我能想到的最佳解决方案。
答案 1 :(得分:0)
如果有人需要这个答案,我自己想出来了。这是可能的,但需要采用不同的方法。首先,请求上下文处理器不适合这种情况。他们相当愚蠢,因为他们只是得到一些东西,并坚持在上下文中。他们唯一的优势是他们的全球性。
我的上下文处理器:
def contact_form(request):
"""
Gets the contact form and adds it to the request context.
You almost certainly don't want to do this.
"""
form = ContactForm()
return {'contact_form': form}
表单的本质是它们在被Django的验证机制处理后表现不同,具体来说ContactForm()
是unbound form并且永远是FormMixin
。您不希望这样做(除非您想要一个只显示但不起作用的表单)。应编辑TEMPLATE_CONTEXT_PROCESSORS
以删除此处理器。
现在,显示表单的负担又回到了视图上,这也意味着任何视图都必须能够处理POST请求。这意味着需要编辑想要联系表单的每个视图,但我们可以使用基于类的视图和mixin的强大功能来处理大部分重复。
ServicesView
与TemplateView
几乎相同,除了使用可处理表单的mixin。这样,模板名称始终保持不变(我的原始问题),但具有额外的形式功能。
class ServicesView(ContactMixin, TemplateView):
template_name = 'services/services.html'
services = ServicesView.as_view()
ContactMixin
使用ProcessFormView
来创建和显示表单,使用different kinds of requests来处理表单的GET和POST请求。并且由于表单的性质随an example in the docs(未提交,已提交和无效,已提交且有效)而变化,因此需要使用正确的表单类实例更新get_context_data
。最后,我们可能希望为表单添加前缀(命名空间),因为它可以在任何地方使用,并且当另一个可能的表单可以POST到同一视图时,我们希望避免冲突。因此,mixin是:
class ContactMixin(FormMixin, ProcessFormView):
form_class = ContactForm
success_url = reverse_lazy('contact_done')
def get_form_kwargs(self):
kwargs = super(ContactMixin, self).get_form_kwargs()
kwargs['prefix'] = 'contact'
return kwargs
def get_context_data(self, **kwargs):
context = super(ContactMixin, self).get_context_data(**kwargs)
form_class = self.get_form_class()
context['contact_form'] = self.get_form(form_class)
return context
def form_valid(self, form):
form.send_email()
return super(ContactMixin, self).form_valid(form)
self.get_form_class()
的微妙之处几乎失去了我,如果它不是StackOverflow answer(不做什么,嘿)和另一个{{3}},我通常只会说self.form_class
,忽略了表格的处理。
现在,我只需将ContactMixin
添加到任意视图,将{% include "includes/contact.html" %}
添加到任何模板。