Passing a Django form to a template tag

时间:2016-10-20 19:47:18

标签: django wagtail templatetags

I'm trying to render a Django form on every page of my Wagtail site in a jQuery slideout box. I've created a template tag that is currently rendering the box, but the form is not showing up. I'm thinking that I'm incorrectly passing the form variable. My template tag file looks like this:

from django import template

from django.shortcuts import render, redirect
from django.template.loader import get_template
from django.core.mail import EmailMessage
from django.template import Context

from .forms import DemoForm

register = template.Library()


@register.inclusion_tag('demo_form.html')
def book_a_demo(request):
   form = DemoForm

   if request.method == 'POST':
        demo_form = form(data=request.POST)

        if demo_form.is_valid():
            contact_name = request.POST.get('name', '')
            company_name = request.POST.get('company', '')
            contact_email = request.POST.get('email', '')
            contact_phone = request.POST.get('phone', '')

            # Email the profile with the
            # contact information
            template = get_template('contact_template.txt')
            context = Context({
                'contact_name': contact_name,
                'company_name': company_name,
                'contact_email': contact_email,
                'contact_phone': contact_phone,
            })
            content = template.render(context)

            email = EmailMessage(
                "Request to Book a Demo",
                content,
                "domain" +'',
                ['example@email.com'],
                headers = {'Reply-To': contact_email }
            )
            email.send()
            return render(request, 'demo_form_landing.html')

   return render(request, 'demo_form.html', {'form': form})

demo_form.html looks like this:

{% load static %}

<div id="feedback">
  <div id="feedback-tab">Book a Demo</div>
  <div id="feedback-form" style='display:block;' class="col-xs-4 col-md-4 panel panel-default">
    <form role="form" action="" method="post" class="form panel-body">
      {% csrf_token %}
      {{ form.as_p }}
      <button class="btn btn-primary pull-right" type="submit">Send</button>
    </form>
  </div>
</div>

My form looks like this:

from django import forms


class DemoForm(forms.Form):
    name = forms.CharField(initial='Your Name', max_length=100)
    company = forms.CharField(initial='Company Name', max_length=100)
    email = forms.EmailField(initial='Email')
    phone = forms.CharField(initial='Phone Number', max_length=100)

The template tag I'm using to try to render it in the main base.html is {% book_a_demo request %}

Any idea what I'm doing wrong? I don't get any errors; it just doesn't appear. I've been stuck on this for hours and it's driving me crazy.

2 个答案:

答案 0 :(得分:3)

When using inclusion_tag, you shouldn't call render yourself. You should return the context dictionary (for example: return {'form': form}) - Django will then take care of rendering the template you named in the @register.inclusion_tag('demo_form.html') declaration.

I would advise against trying to handle the if request.method == 'POST': logic within the tag, as that will be triggered any time any page on your site is rendered in response to a POST request - regardless of whether the POST request had anything to do with your DemoForm. Instead, you should set up a Django view to handle those form submissions, and put the URL to that view in the form's action attribute.

答案 1 :(得分:0)

请求不是POST或is_valid()为false时返回什么?我通常使用这样的模式(注意最后的变化):

from .forms import DemoForm

register = template.Library()

@register.inclusion_tag('demo_form.html')
def book_a_demo(request):
    form = DemoForm

    if request.method == 'POST':
        demo_form = form(data=request.POST)

        if demo_form.is_valid():
            contact_name = request.POST.get('name', '')
            company_name = request.POST.get('company', '')
            contact_email = request.POST.get('email', '')
            contact_phone = request.POST.get('phone', '')

            # Email the profile with the
            # contact information
            template = get_template('contact_template.txt')
            context = Context({
                'contact_name': contact_name,
                'company_name': company_name,
                'contact_email': contact_email,
                'contact_phone': contact_phone,
            })
            content = template.render(context)

            email = EmailMessage(
                "Request to Book a Demo",
                content,
                "domain" +'',
                ['example@email.com'],
                headers = {'Reply-To': contact_email }
            )
            email.send()
            return render(request, 'demo_form_landing.html')
    else:
        demo_form = form()

    return render(request, 'demo_form.html', {'form': demo_form})