Plain is headed towards 1.0! Subscribe for development updates →

Forms

HTML form handling and validation.

The Form and Field classes help output, parse, and validate form data from an HTTP request. Unlike other frameworks, the HTML inputs are not rendered automatically, though there are some helpers for you to do your own rendering.

With forms, you will typically use one of the built-in view classes to tie everything together.

from plain import forms
from plain.views import FormView


class ContactForm(forms.Form):
    email = forms.EmailField()
    message = forms.CharField()


class ContactView(FormView):
    form_class = ContactForm
    template_name = "contact.html"

Then in your template, you can render the form fields.

{% extends "base.html" %}

{% block content %}

<form method="post">
    {{ csrf_input }}

    <!-- Render general form errors -->
    {% for error in form.non_field_errors %}
    <div>{{ error }}</div>
    {% endfor %}

    <div>
        <label for="{{ form.email.html_id }}">Email</label>
        <input
            required
            type="email"
            name="{{ form.email.html_name }}"
            id="{{ form.email.html_id }}"
            value="{{ form.email.value }}">

        {% if form.email.errors %}
        <div>{{ form.email.errors|join(', ') }}</div>
        {% endif %}
    </div>

    <div>
        <label for="{{ form.message.html_id }}">Message</label>
        <textarea
            required
            rows="10"
            name="{{ form.message.html_name }}"
            id="{{ form.message.html_id }}">{{ form.message.value }}</textarea>

        {% if form.message.errors %}
        <div>{{ form.message.errors|join(', ') }}</div>
        {% endif %}
    </div>

    <button type="submit">Submit</button>
</form>

{% endblock %}

With manual form rendering, you have full control over the HTML classes, attributes, and JS behavior. But in large applications the form rendering can become repetitive. You will often end up re-using certain patterns in your HTML which can be abstracted away using Jinja includes, macros, or plain.elements.