paper-forms


Namepaper-forms JSON
Version 0.5.3 PyPI version JSON
download
home_pagehttps://github.com/dldevinc/paper-forms
SummaryA form templating app for Django
upload_time2024-04-15 08:16:37
maintainerMihail Mishakin
docs_urlNone
authorMihail Mishakin
requires_python>=3.9
licenseBSD license
keywords
VCS
bugtrack_url
requirements jinja2 django-jinja jinja2-simple-tags pytest pytest-cov pytest-django pytest-xdist
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # paper-forms

This library provides tools to simplify and customize the form rendering process in Django. 
It includes the `BaseComposer` class for centralized management of form settings and extends 
the functionality of `BoundField` for convenient customization of form fields.

[![PyPI](https://img.shields.io/pypi/v/paper-forms.svg)](https://pypi.org/project/paper-forms/)
[![Build Status](https://github.com/dldevinc/paper-forms/actions/workflows/tests.yml/badge.svg)](https://github.com/dldevinc/paper-forms)
[![Software license](https://img.shields.io/pypi/l/paper-forms.svg)](https://pypi.org/project/paper-forms/)

### Compatibility

-   `python` >= 3.9
-   `django` >= 3.2

### Features

-   [Jinja2](https://jinja.palletsprojects.com/) support.
-   [django-jinja](https://github.com/niwinz/django-jinja) support.

## Table of Contents

1. [Installation](#Installation)
2. [Basic Usage](#Basic-Usage)
3. [Composer Configuration](#Composer-Configuration)
   1. [Specifying Custom Template Names](#Specifying-Custom-Template-Names)
   2. [Customizing Form Field Rendering in Composer](#Customizing-Form-Field-Rendering-in-Composer)
   3. [Customizing Composer Class](#Customizing-Composer-Class)
4. [Template Tags](#Template-Tags)
5. [Common Issues and Workarounds](#Common-Issues-and-Workarounds)

## Installation

To get started with `paper-forms`, you need to install the library using `pip`. 
Ensure you have Python 3.9 or later installed in your environment.

```shell
pip install paper-forms
```

Next, add "paper_forms" to the `INSTALLED_APPS` in your Django project's `settings.py`:

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

## Basic Usage

Start by creating a simple Django form. No mixins or third-party classes are required. 
Just define your form as you normally would using Django's `forms` module.

```python
# forms.py
from django import forms

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

Now, let's render the form in your template using the `{% field %}` template tag 
provided by `paper-forms`. This tag allows you to render form fields with enhanced 
customization.

```html
<!-- example_template.html -->
{% load paper_forms %}

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

The rendered HTML will be similar to the standard Django form rendering, but with 
the added flexibility provided by `paper-forms`. This sets the foundation for integrating 
`paper-forms` seamlessly into your Django project.

## Composer Configuration

The real power of `paper-forms` lies in the ability to customize form rendering 
using the `BaseComposer` class. Let's explore how you can leverage this class to tailor 
the rendering of your forms.

One of the key features of `paper-forms` is the ability to customize form widgets. 
In your Django form, you can define a `Composer` class that inherits from `BaseComposer` 
to specify different widgets for specific fields.

```python
# forms.py
from django import forms
from paper_forms.composer import BaseComposer

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

    class Composer(BaseComposer):
        widgets = {
            "password": forms.PasswordInput,
        }
```

In this example, the `Composer` class defines a custom widget for the "password" field. 
This allows you to have fine-grained control over the rendering of individual form fields.

`paper-forms` also allows you to set labels and help text for form fields, either 
globally or on a per-field basis.

```python
# forms.py
from django import forms
from paper_forms.composer import BaseComposer

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

    class Composer(BaseComposer):
        labels = {
            "name": "Your Full Name",
            "age": "Your Age",
        }
        help_texts = {
            "name": "Enter your full name as it appears on official documents.",
            "age": "Please provide your current age.",
        }
```

Here, the `Composer` class provides labels and help text for the "name" and "age" fields, 
offering clear instructions to users interacting with your forms.

Additionally, developers can enhance the customization of the form's appearance 
by utilizing the `error_css_class` and `required_css_class` attributes 
within the `Composer` class. These attributes allow you to define specific CSS classes 
for handling errors and indicating required fields, respectively. Notably, any values 
set for these attributes in the `Composer` class take precedence over those specified 
at the form level.

### Specifying Custom Template Names

When using `paper-forms`, you have the flexibility to create custom templates for 
individual form fields. This can be achieved by leveraging the `Composer` class 
and specifying custom template names for each field. Let's go through an example 
of how a custom form field template might look:

Assume you have a Django form with a field named "name," and you want to create 
a custom template for rendering this specific field.

1.  **Create the Custom Template**<br>
    Create a new HTML file, let's call it `custom_field.html`, and place 
    it in your Django app's templates directory. Here's a simplified example of how 
    the template might look:
    ```html
    <!-- custom_field.html -->

    <div class="form-field {{ css_classes }}">
        <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>
    ```
    In this example, the template includes a custom structure for rendering 
    the form field, including a label, the actual form widget, error messages, 
    and help text.
2.  **Update the Composer Class**<br>
    Now, update the `Composer` class in your Django form to specify the custom 
    template name for the "name" field:
    ```python
    from django import forms
    from paper_forms.composer import BaseComposer

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

        class Composer(BaseComposer):
            template_names = {
                "name": "path/to/custom_field.html",
            }
    ```
    Ensure that the path provided in template_names matches the location of your custom 
    template file.
3.  **Render the Form in Your Template**<br>
    In your Django template where you render the form, use the `{% field %}` template 
    tag for the "name" field:
    ```html
    {% load paper_forms %}

    <form method="post">
        {% field form.name %}
        {% field form.age %}
        <button type="submit">Submit</button>
    </form>
    ```
    When the form is rendered, the "name" field will use your custom template, 
    while other fields will follow the default rendering.

By following these steps, you can create and apply custom templates for specific form 
fields, providing a tailored look and feel for different parts of your Django forms.

### Customizing Form Field Rendering in Composer

The `paper-forms` library provides extensive flexibility through the `Composer` class, 
allowing you to customize the rendering of form fields. In addition to specifying custom 
templates, you can achieve advanced customization by overriding methods in the 
`BaseComposer` class. Let's explore an example of how to override methods to replace 
`labels` with `placeholders` across all form fields.

Suppose you want to make a global change to the rendering of form fields, replacing 
labels with placeholders.

Step 1: Create a Custom Composer.

Create a custom `Composer` subclass with the desired customization for form 
field rendering.

```python
# composers.py
from paper_forms.composer import BaseComposer

class CustomComposer(BaseComposer):
    placeholders: dict = None

    def get_label(self, name, widget):
        # Override get_label method to return an empty string 
        # for all fields.
        return ""

    def build_widget_attrs(self, name, attrs, widget):
        attrs = super().build_widget_attrs(name, attrs, widget)
        placeholder = attrs.get("placeholder")
        if placeholder is None and self.placeholders:
            placeholder = self.placeholders[name]
        if placeholder:
            attrs["placeholder"] = placeholder
        return attrs
```

Step 2: Use Custom Composer in a Django Form.

Apply the custom `CustomComposer` class to a Django form.

```python
# forms.py
from django import forms
from .composers import CustomComposer


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

    class Composer(CustomComposer):
        placeholders = {
            "name": "Enter your name",
            "age": "Enter your age",
        }
```

Step 3: Render the Form in Your Template.

Use the `{% field %}` template tag to render the form in your template.

```html
{% load paper_forms %}

<form method="post">
    {% field form.name %}
    {% field form.age %}
    <button type="submit">Submit</button>
</form>
```

With this setup, the "name" and "age" fields will have placeholders instead of labels.

### Customizing Composer Class

In addition to the specific methods discussed earlier, the `BaseComposer` class 
in the `paper-forms` library provides several other methods that developers can override 
to further customize form field rendering. Below are some of the additional methods 
available for customization:

`get_widget(self, name: str) -> Widget`

Retrieves a widget for a specific form field. By default, it looks up the widget 
in the `widgets` dictionary. If `None` is returned, the default widget for the field 
will be used.

`get_template_name(self, name: str, widget: Widget) -> str`

Determines the template name to be used for rendering a form field. It considers 
hidden widgets, specific template names in the template_names dictionary, and 
falls back to the default template name.

`get_default_template_name(self, name: str, widget: Widget) -> str`

This method plays a crucial role in simplifying the creation of Composer classes for 
frameworks like Bootstrap. This method is designed to facilitate the customization 
of form field templates without affecting the ability to specify template paths via 
the `template_names` attribute in the `Composer` class.

When rendering a form field, the `get_default_template_name` method is called 
to determine the default template name based on the provided field name and widget. 
This method can be overridden in custom Composer classes to set a default template name, 
allowing for a more streamlined implementation of framework-specific Composers.

```python
from django.forms.widgets import TextInput, NumberInput
from paper_forms.composer import BaseComposer

class FrameworkComposer(BaseComposer):
    def get_default_template_name(self, name, widget) -> str:
        if isinstance(widget, TextInput):
            return f"bootstrap/text_field.html"
        elif isinstance(widget, NumberInput):
            return f"bootstrap/number_field.html"

        # Fall back to the default behavior
        return super().get_default_template_name(name, widget)
```

`get_label(self, name: str, widget: Widget) -> Optional[str]`

Retrieves the label for a form field. It looks up the label in the `labels` dictionary.
If `None` is returned, the default label for the field will be used.

`get_help_text(self, name: str, widget: Widget) -> Optional[str]`

Retrieves the help text for a form field. It looks up the help text in the `help_texts` 
dictionary. If `None` is returned, the default help text for the field will be used.

`get_css_classes(self, name: str, widget: Widget) -> Optional[str]`

Retrieves the CSS classes for a form field. It looks up the CSS classes 
in the `css_classes` dictionary.

`build_widget_attrs(self, name: str, attrs: Optional[dict], widget: Widget) -> dict`

Builds and customizes the attributes for a form field's widget. Developers can add, 
remove, or modify attributes based on field names or other criteria.

`build_context(self, name: str, context: Optional[dict], widget: Widget) -> dict`

Builds the context to be passed to the form field template. Developers can add 
or modify context variables based on field names or other conditions.

## Template Tags

`paper-forms` provides template tags to simplify the integration of the library into 
your Django templates. The primary tag is `{% field %}`, which allows you to render 
form fields with enhanced customization options.

The `{% field %}` tag is the key to leveraging the features provided by `paper-forms`. 
It allows you to render form fields with various attributes and context variables.

```html
{% load paper_forms %}

<form method="post">
  {% field form.name placeholder="Enter your name" %}
  {% field form.age placeholder="Enter your age" _style="light" %}
</form>
```

In this example, the `{% field %}` tag is used to render the "name" and "age" fields 
of the form. Attributes such as `placeholder` and `style` are passed as parameters 
to customize the rendering.

The `{% field %}` tag supports adding variables to the form field template using 
the "_" prefix in the template tag parameters. These variables become part 
of the template context for the form field.

In the example above, the `placeholder` attribute is a widget attribute, while 
the `_style` is a template context variable. Parameters with a leading underscore, 
such as `_style`, are treated as template context variables.

## Configuration

`paper-forms` provides additional configuration options that you can set in your 
Django project's settings.

You can specify the default `Composer` class to be used for any form that doesn't specify 
a particular composer. This is set using the `PAPER_FORMS_DEFAULT_COMPOSER` setting.

```python
# settings.py

PAPER_FORMS_DEFAULT_COMPOSER = "myapp.composers.CustomComposer"
```

Here, `myapp.composers.CustomComposer` is the custom composer class you want to use 
as the default.

The default form renderer can be set using the `PAPER_FORMS_DEFAULT_FORM_RENDERER` setting.

```python
# settings.py

PAPER_FORMS_DEFAULT_FORM_RENDERER = "django.forms.renderers.TemplatesSetting"
```

In this example, `django.forms.renderers.TemplatesSetting` is used as the default 
form renderer.

## Common Issues and Workarounds

In the course of using `paper-forms`, you may encounter some common issues. This section 
provides explanations and workarounds for these issues to help you navigate potential 
challenges.

### Dashes in Attribute Names

If you are trying to specify an attribute with dashes in the `{% field %}` template tag, 
like `data-src`, you might face limitations. This is due to the restrictive nature of 
`@simple_tag`, which [does not allow dashes]((https://code.djangoproject.com/ticket/21077))
in kwargs names.

To overcome this limitation, use double underscores. All double underscores in 
`{% field %}` arguments are replaced with single dashes. For example:

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

This would render to something like

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

### `FORM_RENDERER` Setting with Third-Party Template Engines

If you are using `django-jinja` or any other third-party template engine as your default
template engine, and you want to use it for your form field templates, you might face 
challenges. Django's form widgets are rendered using form renderers, and changing the 
`FORM_RENDERER` setting can break the admin interface.

Follow these steps to work around this problem:

1.  Make built-in widget templates searchable:
    ```python
    # 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 `TemplateSetting` renderer for your forms or implement your own. You can achieve 
    this in several ways:
    * Set the `PAPER_FORMS_DEFAULT_FORM_RENDERER` setting in `settings.py`:
      ```python
      # settings.py

      PAPER_FORMS_DEFAULT_FORM_RENDERER = "django.forms.renderers.TemplatesSetting"
      ```
    * Specify the `default_renderer` attribute in your form:
      ```python
      from django import forms
      from django.forms.renderers import TemplatesSetting

      class ExampleForm(forms.Form):
          default_renderer = TemplatesSetting
          # ...
      ```
    * Set the `renderer` field in your `Composer` class:
      ```python
      from django import forms
      from paper_forms.composer import BaseComposer

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

          class Composer(BaseComposer):
              renderer = "django.forms.renderers.TemplatesSetting"
      ```

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/dldevinc/paper-forms",
    "name": "paper-forms",
    "maintainer": "Mihail Mishakin",
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": "x896321475@gmail.com",
    "keywords": null,
    "author": "Mihail Mishakin",
    "author_email": "x896321475@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/64/01/50a62e8ac86c3bb72cb1291a9ac97a455d7d2b61612ab5c16cf8108c62f3/paper_forms-0.5.3.tar.gz",
    "platform": "OS Independent",
    "description": "# paper-forms\n\nThis library provides tools to simplify and customize the form rendering process in Django. \nIt includes the `BaseComposer` class for centralized management of form settings and extends \nthe functionality of `BoundField` for convenient customization of form fields.\n\n[![PyPI](https://img.shields.io/pypi/v/paper-forms.svg)](https://pypi.org/project/paper-forms/)\n[![Build Status](https://github.com/dldevinc/paper-forms/actions/workflows/tests.yml/badge.svg)](https://github.com/dldevinc/paper-forms)\n[![Software license](https://img.shields.io/pypi/l/paper-forms.svg)](https://pypi.org/project/paper-forms/)\n\n### Compatibility\n\n-   `python` >= 3.9\n-   `django` >= 3.2\n\n### Features\n\n-   [Jinja2](https://jinja.palletsprojects.com/) support.\n-   [django-jinja](https://github.com/niwinz/django-jinja) support.\n\n## Table of Contents\n\n1. [Installation](#Installation)\n2. [Basic Usage](#Basic-Usage)\n3. [Composer Configuration](#Composer-Configuration)\n   1. [Specifying Custom Template Names](#Specifying-Custom-Template-Names)\n   2. [Customizing Form Field Rendering in Composer](#Customizing-Form-Field-Rendering-in-Composer)\n   3. [Customizing Composer Class](#Customizing-Composer-Class)\n4. [Template Tags](#Template-Tags)\n5. [Common Issues and Workarounds](#Common-Issues-and-Workarounds)\n\n## Installation\n\nTo get started with `paper-forms`, you need to install the library using `pip`. \nEnsure you have Python 3.9 or later installed in your environment.\n\n```shell\npip install paper-forms\n```\n\nNext, add \"paper_forms\" to the `INSTALLED_APPS` in your Django project's `settings.py`:\n\n```python\nINSTALLED_APPS = (\n    # ...\n    \"paper_forms\",\n)\n```\n\n## Basic Usage\n\nStart by creating a simple Django form. No mixins or third-party classes are required. \nJust define your form as you normally would using Django's `forms` module.\n\n```python\n# forms.py\nfrom django import forms\n\nclass ExampleForm(forms.Form):\n    name = forms.CharField()\n    age = forms.IntegerField()\n```\n\nNow, let's render the form in your template using the `{% field %}` template tag \nprovided by `paper-forms`. This tag allows you to render form fields with enhanced \ncustomization.\n\n```html\n<!-- example_template.html -->\n{% load paper_forms %}\n\n<form method=\"post\">\n  {% field form.name %}\n  {% field form.age %}\n</form>\n```\n\nThe rendered HTML will be similar to the standard Django form rendering, but with \nthe added flexibility provided by `paper-forms`. This sets the foundation for integrating \n`paper-forms` seamlessly into your Django project.\n\n## Composer Configuration\n\nThe real power of `paper-forms` lies in the ability to customize form rendering \nusing the `BaseComposer` class. Let's explore how you can leverage this class to tailor \nthe rendering of your forms.\n\nOne of the key features of `paper-forms` is the ability to customize form widgets. \nIn your Django form, you can define a `Composer` class that inherits from `BaseComposer` \nto specify different widgets for specific fields.\n\n```python\n# forms.py\nfrom django import forms\nfrom paper_forms.composer import BaseComposer\n\nclass ExampleForm(forms.Form):\n    name = forms.CharField()\n    password = forms.CharField()\n\n    class Composer(BaseComposer):\n        widgets = {\n            \"password\": forms.PasswordInput,\n        }\n```\n\nIn this example, the `Composer` class defines a custom widget for the \"password\" field. \nThis allows you to have fine-grained control over the rendering of individual form fields.\n\n`paper-forms` also allows you to set labels and help text for form fields, either \nglobally or on a per-field basis.\n\n```python\n# forms.py\nfrom django import forms\nfrom paper_forms.composer import BaseComposer\n\nclass ExampleForm(forms.Form):\n    name = forms.CharField()\n    age = forms.IntegerField()\n\n    class Composer(BaseComposer):\n        labels = {\n            \"name\": \"Your Full Name\",\n            \"age\": \"Your Age\",\n        }\n        help_texts = {\n            \"name\": \"Enter your full name as it appears on official documents.\",\n            \"age\": \"Please provide your current age.\",\n        }\n```\n\nHere, the `Composer` class provides labels and help text for the \"name\" and \"age\" fields, \noffering clear instructions to users interacting with your forms.\n\nAdditionally, developers can enhance the customization of the form's appearance \nby utilizing the `error_css_class` and `required_css_class` attributes \nwithin the `Composer` class. These attributes allow you to define specific CSS classes \nfor handling errors and indicating required fields, respectively. Notably, any values \nset for these attributes in the `Composer` class take precedence over those specified \nat the form level.\n\n### Specifying Custom Template Names\n\nWhen using `paper-forms`, you have the flexibility to create custom templates for \nindividual form fields. This can be achieved by leveraging the `Composer` class \nand specifying custom template names for each field. Let's go through an example \nof how a custom form field template might look:\n\nAssume you have a Django form with a field named \"name,\" and you want to create \na custom template for rendering this specific field.\n\n1.  **Create the Custom Template**<br>\n    Create a new HTML file, let's call it `custom_field.html`, and place \n    it in your Django app's templates directory. Here's a simplified example of how \n    the template might look:\n    ```html\n    <!-- custom_field.html -->\n\n    <div class=\"form-field {{ css_classes }}\">\n        <label for=\"{{ widget.attrs.id }}\">{{ label }}</label>\n \n        <!-- include default widget template -->\n        {% include widget.template_name %}\n\n        <!-- show field errors -->\n        {% if errors %}\n        <ul>\n            {% for error in errors %}\n            <li>{{ error }}</li>\n            {% endfor %}\n        </ul>\n        {% endif %}\n\n        <!-- show help text -->\n        {% if help_text %}\n        <small>{{ help_text }}</small>\n        {% endif %}\n    </div>\n    ```\n    In this example, the template includes a custom structure for rendering \n    the form field, including a label, the actual form widget, error messages, \n    and help text.\n2.  **Update the Composer Class**<br>\n    Now, update the `Composer` class in your Django form to specify the custom \n    template name for the \"name\" field:\n    ```python\n    from django import forms\n    from paper_forms.composer import BaseComposer\n\n    class ExampleForm(forms.Form):\n        name = forms.CharField()\n        age = forms.IntegerField()\n\n        class Composer(BaseComposer):\n            template_names = {\n                \"name\": \"path/to/custom_field.html\",\n            }\n    ```\n    Ensure that the path provided in template_names matches the location of your custom \n    template file.\n3.  **Render the Form in Your Template**<br>\n    In your Django template where you render the form, use the `{% field %}` template \n    tag for the \"name\" field:\n    ```html\n    {% load paper_forms %}\n\n    <form method=\"post\">\n        {% field form.name %}\n        {% field form.age %}\n        <button type=\"submit\">Submit</button>\n    </form>\n    ```\n    When the form is rendered, the \"name\" field will use your custom template, \n    while other fields will follow the default rendering.\n\nBy following these steps, you can create and apply custom templates for specific form \nfields, providing a tailored look and feel for different parts of your Django forms.\n\n### Customizing Form Field Rendering in Composer\n\nThe `paper-forms` library provides extensive flexibility through the `Composer` class, \nallowing you to customize the rendering of form fields. In addition to specifying custom \ntemplates, you can achieve advanced customization by overriding methods in the \n`BaseComposer` class. Let's explore an example of how to override methods to replace \n`labels` with `placeholders` across all form fields.\n\nSuppose you want to make a global change to the rendering of form fields, replacing \nlabels with placeholders.\n\nStep 1: Create a Custom Composer.\n\nCreate a custom `Composer` subclass with the desired customization for form \nfield rendering.\n\n```python\n# composers.py\nfrom paper_forms.composer import BaseComposer\n\nclass CustomComposer(BaseComposer):\n    placeholders: dict = None\n\n    def get_label(self, name, widget):\n        # Override get_label method to return an empty string \n        # for all fields.\n        return \"\"\n\n    def build_widget_attrs(self, name, attrs, widget):\n        attrs = super().build_widget_attrs(name, attrs, widget)\n        placeholder = attrs.get(\"placeholder\")\n        if placeholder is None and self.placeholders:\n            placeholder = self.placeholders[name]\n        if placeholder:\n            attrs[\"placeholder\"] = placeholder\n        return attrs\n```\n\nStep 2: Use Custom Composer in a Django Form.\n\nApply the custom `CustomComposer` class to a Django form.\n\n```python\n# forms.py\nfrom django import forms\nfrom .composers import CustomComposer\n\n\nclass ExampleForm(forms.Form):\n    name = forms.CharField()\n    age = forms.IntegerField()\n\n    class Composer(CustomComposer):\n        placeholders = {\n            \"name\": \"Enter your name\",\n            \"age\": \"Enter your age\",\n        }\n```\n\nStep 3: Render the Form in Your Template.\n\nUse the `{% field %}` template tag to render the form in your template.\n\n```html\n{% load paper_forms %}\n\n<form method=\"post\">\n    {% field form.name %}\n    {% field form.age %}\n    <button type=\"submit\">Submit</button>\n</form>\n```\n\nWith this setup, the \"name\" and \"age\" fields will have placeholders instead of labels.\n\n### Customizing Composer Class\n\nIn addition to the specific methods discussed earlier, the `BaseComposer` class \nin the `paper-forms` library provides several other methods that developers can override \nto further customize form field rendering. Below are some of the additional methods \navailable for customization:\n\n`get_widget(self, name: str) -> Widget`\n\nRetrieves a widget for a specific form field. By default, it looks up the widget \nin the `widgets` dictionary. If `None` is returned, the default widget for the field \nwill be used.\n\n`get_template_name(self, name: str, widget: Widget) -> str`\n\nDetermines the template name to be used for rendering a form field. It considers \nhidden widgets, specific template names in the template_names dictionary, and \nfalls back to the default template name.\n\n`get_default_template_name(self, name: str, widget: Widget) -> str`\n\nThis method plays a crucial role in simplifying the creation of Composer classes for \nframeworks like Bootstrap. This method is designed to facilitate the customization \nof form field templates without affecting the ability to specify template paths via \nthe `template_names` attribute in the `Composer` class.\n\nWhen rendering a form field, the `get_default_template_name` method is called \nto determine the default template name based on the provided field name and widget. \nThis method can be overridden in custom Composer classes to set a default template name, \nallowing for a more streamlined implementation of framework-specific Composers.\n\n```python\nfrom django.forms.widgets import TextInput, NumberInput\nfrom paper_forms.composer import BaseComposer\n\nclass FrameworkComposer(BaseComposer):\n    def get_default_template_name(self, name, widget) -> str:\n        if isinstance(widget, TextInput):\n            return f\"bootstrap/text_field.html\"\n        elif isinstance(widget, NumberInput):\n            return f\"bootstrap/number_field.html\"\n\n        # Fall back to the default behavior\n        return super().get_default_template_name(name, widget)\n```\n\n`get_label(self, name: str, widget: Widget) -> Optional[str]`\n\nRetrieves the label for a form field. It looks up the label in the `labels` dictionary.\nIf `None` is returned, the default label for the field will be used.\n\n`get_help_text(self, name: str, widget: Widget) -> Optional[str]`\n\nRetrieves the help text for a form field. It looks up the help text in the `help_texts` \ndictionary. If `None` is returned, the default help text for the field will be used.\n\n`get_css_classes(self, name: str, widget: Widget) -> Optional[str]`\n\nRetrieves the CSS classes for a form field. It looks up the CSS classes \nin the `css_classes` dictionary.\n\n`build_widget_attrs(self, name: str, attrs: Optional[dict], widget: Widget) -> dict`\n\nBuilds and customizes the attributes for a form field's widget. Developers can add, \nremove, or modify attributes based on field names or other criteria.\n\n`build_context(self, name: str, context: Optional[dict], widget: Widget) -> dict`\n\nBuilds the context to be passed to the form field template. Developers can add \nor modify context variables based on field names or other conditions.\n\n## Template Tags\n\n`paper-forms` provides template tags to simplify the integration of the library into \nyour Django templates. The primary tag is `{% field %}`, which allows you to render \nform fields with enhanced customization options.\n\nThe `{% field %}` tag is the key to leveraging the features provided by `paper-forms`. \nIt allows you to render form fields with various attributes and context variables.\n\n```html\n{% load paper_forms %}\n\n<form method=\"post\">\n  {% field form.name placeholder=\"Enter your name\" %}\n  {% field form.age placeholder=\"Enter your age\" _style=\"light\" %}\n</form>\n```\n\nIn this example, the `{% field %}` tag is used to render the \"name\" and \"age\" fields \nof the form. Attributes such as `placeholder` and `style` are passed as parameters \nto customize the rendering.\n\nThe `{% field %}` tag supports adding variables to the form field template using \nthe \"_\" prefix in the template tag parameters. These variables become part \nof the template context for the form field.\n\nIn the example above, the `placeholder` attribute is a widget attribute, while \nthe `_style` is a template context variable. Parameters with a leading underscore, \nsuch as `_style`, are treated as template context variables.\n\n## Configuration\n\n`paper-forms` provides additional configuration options that you can set in your \nDjango project's settings.\n\nYou can specify the default `Composer` class to be used for any form that doesn't specify \na particular composer. This is set using the `PAPER_FORMS_DEFAULT_COMPOSER` setting.\n\n```python\n# settings.py\n\nPAPER_FORMS_DEFAULT_COMPOSER = \"myapp.composers.CustomComposer\"\n```\n\nHere, `myapp.composers.CustomComposer` is the custom composer class you want to use \nas the default.\n\nThe default form renderer can be set using the `PAPER_FORMS_DEFAULT_FORM_RENDERER` setting.\n\n```python\n# settings.py\n\nPAPER_FORMS_DEFAULT_FORM_RENDERER = \"django.forms.renderers.TemplatesSetting\"\n```\n\nIn this example, `django.forms.renderers.TemplatesSetting` is used as the default \nform renderer.\n\n## Common Issues and Workarounds\n\nIn the course of using `paper-forms`, you may encounter some common issues. This section \nprovides explanations and workarounds for these issues to help you navigate potential \nchallenges.\n\n### Dashes in Attribute Names\n\nIf you are trying to specify an attribute with dashes in the `{% field %}` template tag, \nlike `data-src`, you might face limitations. This is due to the restrictive nature of \n`@simple_tag`, which [does not allow dashes]((https://code.djangoproject.com/ticket/21077))\nin kwargs names.\n\nTo overcome this limitation, use double underscores. All double underscores in \n`{% field %}` arguments are replaced with single dashes. For example:\n\n```html\n{% field form.name data__original__name=\"Name\" %}\n```\n\nThis would render to something like\n\n```html\n<input ... data-original-name=\"Name\" />\n```\n\n### `FORM_RENDERER` Setting with Third-Party Template Engines\n\nIf you are using `django-jinja` or any other third-party template engine as your default\ntemplate engine, and you want to use it for your form field templates, you might face \nchallenges. Django's form widgets are rendered using form renderers, and changing the \n`FORM_RENDERER` setting can break the admin interface.\n\nFollow these steps to work around this problem:\n\n1.  Make built-in widget templates searchable:\n    ```python\n    # settings.py\n\n    from pathlib import Path\n    from django import forms\n\n    TEMPLATES = [\n        {\n            \"NAME\": \"jinja2\",\n            \"BACKEND\": \"django_jinja.backend.Jinja2\",\n            \"DIRS\": [\n                BASE_DIR / \"templates\",\n                Path(forms.__file__).parent / \"jinja2\"\n            ],\n            # ...\n        }\n    ]\n    ```\n\n2.  Use `TemplateSetting` renderer for your forms or implement your own. You can achieve \n    this in several ways:\n    * Set the `PAPER_FORMS_DEFAULT_FORM_RENDERER` setting in `settings.py`:\n      ```python\n      # settings.py\n\n      PAPER_FORMS_DEFAULT_FORM_RENDERER = \"django.forms.renderers.TemplatesSetting\"\n      ```\n    * Specify the `default_renderer` attribute in your form:\n      ```python\n      from django import forms\n      from django.forms.renderers import TemplatesSetting\n\n      class ExampleForm(forms.Form):\n          default_renderer = TemplatesSetting\n          # ...\n      ```\n    * Set the `renderer` field in your `Composer` class:\n      ```python\n      from django import forms\n      from paper_forms.composer import BaseComposer\n\n      class ExampleForm(forms.Form):\n          name = forms.CharField()\n\n          class Composer(BaseComposer):\n              renderer = \"django.forms.renderers.TemplatesSetting\"\n      ```\n",
    "bugtrack_url": null,
    "license": "BSD license",
    "summary": "A form templating app for Django",
    "version": "0.5.3",
    "project_urls": {
        "Homepage": "https://github.com/dldevinc/paper-forms"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "8e3521eef7151041f50fa9575d9096400de07684037f7980164a8a21366c503e",
                "md5": "39fc73b28329149200954a2cb073fd97",
                "sha256": "750c36d1b76dffbf238ace2864db7393e1dbc0f550858a1d4509b9502e80e0c5"
            },
            "downloads": -1,
            "filename": "paper_forms-0.5.3-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "39fc73b28329149200954a2cb073fd97",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": ">=3.9",
            "size": 12248,
            "upload_time": "2024-04-15T08:16:35",
            "upload_time_iso_8601": "2024-04-15T08:16:35.556095Z",
            "url": "https://files.pythonhosted.org/packages/8e/35/21eef7151041f50fa9575d9096400de07684037f7980164a8a21366c503e/paper_forms-0.5.3-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "640150a62e8ac86c3bb72cb1291a9ac97a455d7d2b61612ab5c16cf8108c62f3",
                "md5": "e69edd2aade5db0bbd27fc4241cb024b",
                "sha256": "8dada0d179feeac023e49621293426b4ece54f6f5192f38a4bceab3c9dcc76bc"
            },
            "downloads": -1,
            "filename": "paper_forms-0.5.3.tar.gz",
            "has_sig": false,
            "md5_digest": "e69edd2aade5db0bbd27fc4241cb024b",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 17990,
            "upload_time": "2024-04-15T08:16:37",
            "upload_time_iso_8601": "2024-04-15T08:16:37.331484Z",
            "url": "https://files.pythonhosted.org/packages/64/01/50a62e8ac86c3bb72cb1291a9ac97a455d7d2b61612ab5c16cf8108c62f3/paper_forms-0.5.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-15 08:16:37",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "dldevinc",
    "github_project": "paper-forms",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [
        {
            "name": "jinja2",
            "specs": []
        },
        {
            "name": "django-jinja",
            "specs": []
        },
        {
            "name": "jinja2-simple-tags",
            "specs": []
        },
        {
            "name": "pytest",
            "specs": [
                [
                    "==",
                    "7.4.2"
                ]
            ]
        },
        {
            "name": "pytest-cov",
            "specs": [
                [
                    "==",
                    "4.1.0"
                ]
            ]
        },
        {
            "name": "pytest-django",
            "specs": [
                [
                    "==",
                    "4.5.2"
                ]
            ]
        },
        {
            "name": "pytest-xdist",
            "specs": [
                [
                    "==",
                    "3.3.1"
                ]
            ]
        }
    ],
    "tox": true,
    "lcname": "paper-forms"
}
        
Elapsed time: 0.29112s