【问题标题】:Dynamically get template name in bound Django form在绑定的 Django 表单中动态获取模板名称
【发布时间】:2014-09-19 06:28:29
【问题描述】:

我正在尝试在任意页面上呈现 Django 联系表单。我正在使用请求上下文处理器和模板包含来执行此操作。这使我可以在任何我想要的地方很好地显示表单。然后我有一个接受 POST 请求的特殊 URL(在 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 表单视图在表单无效时有些沉默,因为它的场景大多类似于未绑定的表单,所以最后都只是渲染。由于模板包含,我的情况有所不同。

【问题讨论】:

  • 你能粘贴你的模板吗?
  • 将我的模板添加到原始问题中。

标签: django django-forms django-class-based-views


【解决方案1】:

您可以在每次渲染模板时设置一个会话变量,然后在需要时使用它:

request.session['template']="nameOfTemplate"

.

return render(request, request.session.get('template', 'default.html'), {'contact_form': form})

我知道每次渲染模板时都需要编写一行代码,但这是我能想到的最佳解决方案。

【讨论】:

    【解决方案2】:

    如果有人需要这个答案,我自己想出来的。这是可能的,但需要不同的方法。首先,请求上下文处理器不适合这种情况。他们相当愚蠢,因为他们只得到一次并将其粘贴在上下文中。他们唯一的优势是他们的全球性。

    我的上下文处理器:

    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 并且将永远是。您不想这样做(除非您想要一个简单显示但不起作用的表单)。应编辑 TEMPLATE_CONTEXT_PROCESSORS 以删除此处理器。

    现在显示表单的负担又回到了视图上,这也意味着几乎任何视图都必须能够处理 POST 请求。这意味着需要编辑每个需要联系表单的视图,但我们可以使用基于类的视图和 mixin 的强大功能来处理大部分重复。

    ServicesView 几乎与TemplateView 相同,只是使用了一个可以处理表单的 mixin。这样,模板名称始终保持不变(我原来的问题),但具有额外的表单功能。

    class ServicesView(ContactMixin, TemplateView):
        template_name = 'services/services.html'
    
    services = ServicesView.as_view()
    

    ContactMixin 使用FormMixin 创建和显示一个表单,ProcessFormView 处理表单的 GET 和 POST 请求。并且由于表单的性质随着different kinds of requests(未提交、已提交且无效、已提交且有效)而变化,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)
    

    如果不是因为an example in the docs(不该做什么,呵呵)和另一个StackOverflow answer(我通常只会说self.form_class),我几乎忘记了self.get_form_class() 的微妙之处。忽略表单的处理。

    现在我只需将ContactMixin 添加到任何视图,并将{% include "includes/contact.html" %} 添加到任何模板。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-22
      • 2016-06-25
      • 2012-01-04
      • 2015-12-04
      • 1970-01-01
      • 1970-01-01
      • 2012-02-15
      相关资源
      最近更新 更多