kbdev
kbdev

Reputation: 1315

Passing a Django form to a template tag

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" +'',
                ['[email protected]'],
                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.

Upvotes: 3

Views: 1863

Answers (2)

BottleZero
BottleZero

Reputation: 983

What is returned when the request is not a POST or is_valid() is false? I typically use a pattern like this (note the changes at the end):

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" +'',
                ['[email protected]'],
                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})

Upvotes: 0

gasman
gasman

Reputation: 25292

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.

Upvotes: 4

Related Questions