I wanted to make a Django contact form on website and I found Django crispy forms very useful for that, but it turned out that I can't mix it with Django FormView just like this. Crispy forms have done awesome job in front-end layout, but I can't grab any information from the filled form to my Django app. I've tried this tutorial: Simple Django email form using CBV, but it's outdated and is not helpful at all. Here are my forms.py:
from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
class ContactForm(forms.Form):
name = forms.CharField(
label = "Name:",
max_length = 80,
required = True,
)
email = forms.CharField(
label = "E-mail:",
max_length = 80,
required = True,
)
subject = forms.CharField(
label = "Subject:",
max_length = 80,
required = True,
)
message = forms.CharField(
widget = forms.Textarea,
label = "Message:",
required = True,
)
def __init__(self, *args, **kwargs):
super(ContactForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.add_input(Submit('send', 'Send'))
views.py:
from django.shortcuts import render
from myapp.forms import ContactForm
from django.core.mail import send_mail
from django.views.generic.edit import FormView
class ContactFormView(FormView):
form_class = ContactForm
template_name = "myapp/contact.html"
success_url = '/email_sent/'
def form_valid(self, form):
message = "{name} / {email} said: ".format(
name=form.cleaned_data.get('name'),
email=form.cleaned_data.get('email'))
message += "\n\n{0}".format(form.cleaned_data.get('message'))
send_mail(
subject=form.cleaned_data.get('subject').strip(),
message=message,
from_email='[email protected]',
recipient_list=['[email protected]'],
)
return super(ContactFormView, self).form_valid(form)
def contact(request):
contact_form = ContactFormView()
return render(request, 'myapp/contact.html', {'contact_form': contact_form})
and my template contact.html:
{% extends "layout.html" %}
{% load crispy_forms_tags %}
{% block title %}Contact{% endblock %}
{% block content %}
<h2><b>Contact</b></h2>
<div class="container">
<p>You can e-mail me at: <a href="mailto:[email protected]">[email protected]</a></p>
<br>
<p>Or simply fill the form below:</p>
<br>
{% crispy contact_form %}
</div>
{% endblock %}
What I get is:
Exception Type: TypeErrorException Value:
'ContactFormView' object is not iterable
Any suggestions how to use Django crispy forms with Django FormView?
This doesn't have anything to do with crispy forms. The problem is in this piece of code, where you are treating ContactFormView
as if it's a form.
def contact(request):
contact_form = ContactFormView()
return render(request, 'myapp/contact.html', {'contact_form': contact_form})
However, ContactFormView
is not a form, it's a class based view. You don't need to define another view contact
, you already have a view ContactFormView
.
Change your url pattern to use the class based view:
url(r'^contact/$', ContactFormView.as_view(), name='contact')
Then in your template, include the form with:
{{ form }}}
Once the view is working with regular forms, use the crispy tag so that it is styled as you wish:
{% crispy form %}