Silhouette is a form templating app for Django just like Django Crispy Forms
or Django Floppy Forms.
Unlike these, form templating with Silhouette is exclusively done at the template level. Your form classes don’t need to change.

You no longer have to plague your forms with widgets that are only here to add some css or form helpers simulating html. Your django forms are
used for server-side input validation, your templates are the only ones responsible for making them look awesome.

If you happen to have a team of frontend developers who don’t want to dig deep into the darkness of your
python code to change a class on one of your field’s help text, they’ll probably thank you.
And even if you don’t, you’ll probably be happy to keep your form templating code where it belongs: in your templates.

Silhouette also lets you create global themes and form specific themes to style everything from the form tag down to field errors and widget types.
Since everything happens in templates, you can use template inheritance and blocks to achieve anything you like. Read on.

Installation

pip install django-silhouette

In your settings.py

INSTALLED_APPS = [
...
"silhouette",
...
]

Getting Started

Instead of explaining the internals of Silhouette head-on, let’s get a feel for it by creating a form styled with Twitter’s Bootstrap.
We’ll assume that your layout already includes the bootstrap stylesheet.

This will give you the form as per Bootstrap’s example. We didn’t do anything about errors, but Silhouette will
also render these for free (you could add errors_class="alertalert-danger" to each field to display errors using bootstrap’s alerts).

This is still not ideal though. All our forms should be displayed consistently and there will be a lot of repetition if we need to do this for
every single form.

Let’s create a global theme that will handle all this for us.

Global Themes

In your settings.py, configure the silhouette theme name. By default this is:

SILHOUETTE_THEME = "default"

Let’s change the theme name to bootstrap:

SILHOUETTE_THEME = "bootstrap"

Create a file templates/silhouette/bootstrap/fields/field.html. You could create a template from scratch and render the label,
widget, errors and help text individually (refer to the base field template for an example),
but let’s see how to take advantage of Django’s template inheritance and Silhouette’s base theme

Note that the template is not created under the bootstrap theme, but under the basic_form “theme”. This is the form’s class name BasicForm in underscore notation.

Now, in templates/silhouette/basic_form/controls.html:

<button type="submit" class="btn btn-default">Submit</button>

Note that you could override this in the global theme by modifying templates/silhouette/bootstrap/forms/controls.html instead.

Just like with the global theme, you can override any field, label, widget, field errors, help text in your form by
creating a template in templates/silhouette/basic_form/fields/{{overridden_part}}.html.

Anything usually possible with Django templates is possible with Silhouette.
Silhouette provides a base theme with what we assumed could be useful and generic, but you can ignore it or replace it altogether.

Template Loader

When rendering a template for a field, form or formset, Silhouette tries and find the first template that exists using a list of path patterns.

The general idea is that Silhouette will look for a template from the most specific to the most generic place.

For example, when doing {% field form.field %}, Silhouette will check:

if a template exists for the field in the form’s theme

if one exists for the field’s widget in the form’s theme

if one exists for the field’s widget in the global theme

if one exists for all fields in the form’s theme

if one exists for all fields in the global theme

otherwise, it will fallback to using the base field template shipped with Silhouette

These rules are defined like this in the SILHOUETTE_PATTERNS setting:

{path}/{form}/fields/{field}.html

{path}/{form}/fields/{widget}_field.html

{path}/{theme}/fields/{widget}_field.html

{path}/{form}/fields/field.html

{path}/{theme}/fields/field.html

silhouette/base/fields/field.html

Where {path} is the value of the SILHOUETTE_PATH setting, {theme} is the value of the SILHOUETTE_THEME setting, {form} is the form class
name in underscore notation, {field} is the field name in your form, and {widget} is the widget class name in underscore notation.

Each tag has its own lookup list of patterns. See the default settings
for a full list. For advanced usage or if you simply don’t like the convention and want to use another one, new patterns can be added or the lookup order modified by changing the SILHOUETTE_PATTERNS setting.

Bypassing the Template Lookup

Tags also accept a template argument to render a specific template. For example:

{% field form.field1 template="path/to/field1.html" %}

When using the template argument, field patterns will be ignored.

Overriding Path and Theme

Path and theme can also be overridden for a given tag. For example:

{% field form.field1 path="form-themes" theme="my-theme" %}

When using these arguments, the value of {path} and {theme} are overridden for the given tag, and all tags used within its context.
So in the above example, the widget, label, help_text and errors rendered by field would use the path form-themes and the theme my-theme.