Cookbook

Success and error messages

Starting from release 1.0, envelope.views.ContactView does not set any messages since these were customized by most users anyway. We encourage you to use the excellent django-braces app which provides a FormMessagesMixin designed specifically for this purpose.

The following example shows how to add the mixin to ContactView:

from braces.views import FormMessagesMixin
from envelope.views import ContactView

from django.utils.translation import ugettext_lazy as _


class MyContactView(FormMessagesMixin, ContactView):
    form_valid_message = _(u"Thank you for your message.")
    form_invalid_message = _(u"There was an error in the contact form.")

See the customization section on how to plug the subclassed view into your URLconf.

Check out Django messages documentation to make sure messages are enabled in your project.

Bootstrap integration

Embedding the contact form

From our personal experience with Bootstrap-powered websites, the easiest way to embed the contact form is to use django-crispy-forms. Install it with:

pip install django-crispy-forms

and add crispy_forms to INSTALLED_APPS. From there it’s as simple as adding a crispy template tag to display the form. For example:

{% load envelope_tags crispy_forms_tags %}

...

<form action="{% url 'envelope-contact' %}" method="post">
    {% csrf_token %}
    {% antispam_fields %}
    {% crispy form %}
</form>

To add a submit button, create a custom form using django-crispy-forms helper:

# forms.py
from envelope.forms import ContactForm
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit


class MyContactForm(ContactForm):
    def __init__(self, *args, **kwargs):
        super(MyContactForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.add_input(Submit('submit', 'Submit', css_class='btn-lg'))

And finally link this form to your view:

# views.py
from braces.views import FormMessagesMixin
from envelope.views import ContactView

from django.utils.translation import ugettext_lazy as _

from .forms import MyContactForm


class MyContactView(FormMessagesMixin, ContactView):
    form_invalid_message = _(u"There was an error in the contact form.")
    form_valid_message = _(u"Thank you for your message.")
    form_class = MyContactForm

or just use it in your urls.py if you directly reference ContactView as_view() method:

# urls.py
from django.conf.urls import patterns, url
from envelope.views import ContactView

from .forms import MyContactForm


urlpatterns = patterns('',
    url(r'^contact/', ContactView.as_view(form_class=MyContactForm)),
)

Displaying form messages nicely

GETting the contact form page after POSTing it will give you access to either a success message (form_valid_message) or an error message (form_invalid_message) thanks to django-braces’ FormMessagesMixin. These messages use Django messages tag level so you can use the right Bootstrap class.

We recommend you first override Django’s default message tags as following:

# settings.py
MESSAGE_TAGS = {
    messages.DEBUG: 'debug',
    messages.INFO: 'info',
    messages.SUCCESS: 'success',
    messages.WARNING: 'warning',
    messages.ERROR: 'danger' # 'error' by default
}

Then you can use Django’s tip to display messages with Bootstrap CSS classes such as text-info or alert-warning:

{% if messages %}
    <ul class="messages">
        {% for message in messages %}
            <li {% if message.tags %} class="text-{{ message.tags }}"{% endif %}>
                {{ message }}
            </li>
        {% endfor %}
    </ul>
{% endif %}

Categorized contact form

Although the category field was removed from the default form class in 1.0, you can bring it back to your form using the following subclass:

from envelope.forms import ContactForm

from django import forms
from django.utils.translation import ugettext_lazy as _


class CategorizedContactForm(ContactForm):
    CATEGORY_CHOICES = (
        ('', _("Choose")),
        (10, _("A general question regarding the website")),
        # ... any other choices you can imagine
        (None, _("Other")),
    )
    category = forms.ChoiceField(label=_("Category"), choices=CATEGORY_CHOICES)

    def __init__(self, *args, **kwargs):
        """
        Category choice will be rendered above the subject field.
        """
        super(CategorizedContactForm, self).__init__(*args, **kwargs)
        self.fields.keyOrder = [
            'sender', 'email', 'category', 'subject', 'message',
        ]

    def get_context(self):
        """
        Adds full category description to template variables in order
        to display the category in email body.
        """
        context = super(CategorizedContactForm, self).get_context()
        context['category'] = self.get_category_display()
        return context

    def get_category_display(self):
        """
        Returns the displayed name of the selected category.
        """
        try:
            category = int(self.cleaned_data['category'])
        except (AttributeError, ValueError, KeyError):
            category = None
        return dict(self.CATEGORY_CHOICES).get(category)