Skip to main content

A form templating app for Django

Project description

paper-forms

A form templating app for Django

PyPI Build Status Software license

Compatibility

  • python >= 3.6
  • django >= 2.2

Installation

Install the latest release with pip:

pip install paper-forms

Add paper_forms to your INSTALLED_APPS in settings.py:

INSTALLED_APPS = (
    # ...
    "paper_forms",
)

Features

  • Jinja2 support.
  • django-jinja support.
  • Add or replace form field attributes with a template tag.

⚠ WARNING! paper_forms does not call the widget's render() method. This could be a problem for third-party widgets.

Usage

Let’s create our first Django form.

from django import forms

class ExampleForm(forms.Form):
    name = forms.CharField()
    age = forms.IntegerField()

No mixins. No third-party classes. Just a simple Django form.

Now, let’s render our form by using the {% field %} template tag:

{% load paper_forms %}

<form method="post">
    {% field form.name %}
    {% field form.age %}
</form>

This is exactly the html that you would get:

<form method="post">
    <input type="text" name="name" id="id_name" required />
    <input type="number" name="age" id="id_age" required />
</form>

As you can see, a {% field form.field %} template tag behaves exactly like {{ form.field }}. This is how you can integrate paper-forms with your Django project.

Now, let's add some customization.

Customization

The simplest thing you can do is to add (or replace) attributes to the widget:

{% load paper_forms %}

<form method="post">
    {% field form.name placeholder="Enter your name" %}
    {% field form.age placeholder="Enter your age" title=form.age.label %}
</form>

Result:

<form method="post">
    <input type="text" name="name" id="id_name" placeholder="Enter your name" required />
    <input type="number" name="age" title="Age" required placeholder="Enter your age" id="id_age" />
</form>

Note that you cannot specify an attribute with a dashes, like data-src. This is because @simple_tag is quite restrictive and doesn't allow dashes in kwargs names.

A way to get around this limitation is to use double-underscore. All double-underscores in {% field %} arguments are replaced with single dashes:

{% field form.name data__original__name="Name" %}

would render to something like

<input ... data-original-name="Name" />

Override widget templates with Composer

Composer is a tool which gives you full control over form field rendering.

Example:

from django import forms
from paper_forms.composers.base import BaseComposer


class ExampleForm(forms.Form):
    name = forms.CharField()
    password = forms.CharField()

    class Composer(BaseComposer):
        widgets = {
            "password": forms.PasswordInput
        }
        template_names = {
            "password": "path/to/field_template.html"
        }
        labels = {
            "password": "Enter your password"
        }
        help_texts = {
            "password": "Your password must be 8-20 characters long, "
                        "contain letters and numbers, and must not contain "
                        "spaces, special characters, or emoji."
        }

As you can see, attributes such as widgets, labels and help_texts are very similar to those of the ModelForm's Meta class. The data specified in the Composer fields have the highest priority.

There is also the template_names attribute which allows you to override a form field templates. Form field template context is a widget context, extended with label, errors and help_text values. You can add your own data by overriding the build_widget_context method in your Composer class.

Template example:

<div class="form-field">
    <label for="{{ widget.attrs.id }}">{{ label }}</label>

    <!-- include default widget template -->
    {% include widget.template_name %}

    <!-- show field errors -->
    {% if errors %}
    <ul>
        {% for error in errors %}
        <li>{{ error }}</li>
        {% endfor %}
    </ul>
    {% endif %}

    <!-- show help text -->
    {% if help_text %}
    <small>{{ help_text }}</small>
    {% endif %}
</div>

Create your own Composer subclass for web frameworks

Example:

from django.forms import widgets
from paper_forms.composers.base import BaseComposer


class Bootstrap4(BaseComposer):
    def get_default_template_name(self, widget):
        # Overrides the widget template, but has a lower priority
        # than the 'template_names' attribute of the Composer class.
        if isinstance(widget, widgets.CheckboxInput):
            return "paper_forms/bootstrap4/checkbox.html"
        else:
            return "paper_forms/bootstrap4/input.html"

    def get_default_css_classes(self, widget):
        # Adds default CSS classes that can be overridden
        # in the {% field %} template tag.
        if isinstance(widget, widgets.CheckboxInput):
            return "form-check-input"
        else:
            return "form-control"

Settings

  • PAPER_FORMS_DEFAULT_COMPOSER
    Default Composer class to be used for any Form that don’t specify a particular composer.
    Default: paper_forms.composers.base.BaseComposer

  • PAPER_FORMS_DEFAULT_FORM_RENDERER
    The class that renders form widgets.
    Default: None

A FORM_RENDERER problem

If you use django-jinja (or any other third-party template engine) as your default template engine, you may also want to use it for your form field templates. It's a bit tricky because Django's form widgets are rendered using form renderers.

It means that even if your page are rendered with django-jinja, the form on that page renders through Django Templates.

You should not change FORM_RENDERER setting, because it can break the admin interface. Most of the third-party widgets are designed for the Django Templates.

Two steps are needed to get around this problem.

  1. Make built-in widget templates searcheable.

    # settings.py
    
    from pathlib import Path
    from django import forms
    
    TEMPLATES = [
        {
            "NAME": "jinja2",
            "BACKEND": "django_jinja.backend.Jinja2",
            "DIRS": [
                BASE_DIR / "templates",
                Path(forms.__file__).parent / "jinja2"        # <---
            ],
            # ...
        }
    ]
    
  2. Use TemplateSettings renderer for you forms, or implement your own. There are several ways to do this:

    1. PAPER_FORMS_DEFAULT_FORM_RENDERER setting.

      # settings.py
      
      PAPER_FORMS_DEFAULT_FORM_RENDERER = "django.forms.renderers.TemplatesSetting"
      
    2. Form.default_renderer

      from django import forms
      from django.forms.renderers import TemplatesSetting
      
      class ExampleForm(forms.Form):
          default_renderer = TemplatesSetting
          # ...
      
    3. Composer.renderer field

      from django import forms
      from paper_forms.composers.base import BaseComposer
      
      
      class ExampleForm(forms.Form):
          name = forms.CharField()
      
          class Composer(BaseComposer):
              renderer = "django.forms.renderers.TemplatesSetting"
      

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

paper-forms-0.2.2.tar.gz (13.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

paper_forms-0.2.2-py2.py3-none-any.whl (14.4 kB view details)

Uploaded Python 2Python 3

File details

Details for the file paper-forms-0.2.2.tar.gz.

File metadata

  • Download URL: paper-forms-0.2.2.tar.gz
  • Upload date:
  • Size: 13.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.10.12

File hashes

Hashes for paper-forms-0.2.2.tar.gz
Algorithm Hash digest
SHA256 9d82cfec0af5556e6f5c7e16eed1ca4fac58dc77ed02b044977c1121217a79a9
MD5 c937029eba3042a55a680d5c35ca7a34
BLAKE2b-256 d84940f9a2d33152f1a47598ed11e6c077b1daea3eea8abb1010079b9aee9a0a

See more details on using hashes here.

File details

Details for the file paper_forms-0.2.2-py2.py3-none-any.whl.

File metadata

  • Download URL: paper_forms-0.2.2-py2.py3-none-any.whl
  • Upload date:
  • Size: 14.4 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.10.12

File hashes

Hashes for paper_forms-0.2.2-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 55fd5d4b324fff22d3ece29eb31fcd04aaaa4fe43069f6d9f22beff271d4c5c6
MD5 565f1aa66ed07d9cc1a42ef303f88027
BLAKE2b-256 52d14e4dd9a55fbbe52bcf522bf903a1831a5ce14f7ccc9392b9bf56e4ba3d2f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page