Skip to main content

django_slots = inclusion tag + blocks

Project description

django_slots

django_slots = inclusion tag + blocks

pip install django-slots
INSTALLED_APPS = [
    # ...
    
    'django_slots',
]

Examples

Button example

# app/templatetags/component_tags.py
from django_slots import Library, Component

register = Library()


@register.component
class Button(Component):
    pass
{# app/templates/components/button.html #}
<button>{{ value|default:slot }}</button>

Usage

{% load component_tags %}

{% button/ value="Save" %}

{% button %}
    <div>Save</div>
    <small>and add another</small>
{% /button %}

Details example

# app/templatetags/component_tags.py
from django_slots import Library, Component

register = Library()


@register.block_component
class Details(Component):
    pass
{# app/templates/components/details.html #}
<details>
  <summary>{{ summary|default:slots.summary }}</summary>
  {{ slot }}
</details>

Usage

{% load component_tags %}
{% load slot_tags %}

{% details summary="the summary" %}
    the default slot
{% /details %}

{% details %}
    {% slot summary %}the <b>summary</b>{% /slot %}
    the default slot
{% /details %}

Form example

Python

# app/templatetags/component_tags.py
from django.forms.utils import ErrorList
from django.forms import Form

from django_slots.components import Library, Component, DEFAULT_SLOT_NAME


register = Library()


@register.component
class Button(Component):
    STYLE_CHOICES = ['green', 'red']
    TYPE_CHOICES = ['submit', 'reset', '']

    def get_context_data(
        self, 
        slots: dict[str, str], 
        *,
        type: str = 'submit', 
        name: str ='', 
        value: str = 'Submit', 
        style: str = 'green'
    ):
        if value and DEFAULT_SLOT_NAME in slots:
            raise self.validation_error("use value keyword argument or slot tag.")

        if type not in self.TYPE_CHOICES:
            raise self.validation_error(f"type='{type}' must be one of {self.TYPE_CHOICES!r}")
        
        if style not in self.STYLE_CHOICES:
            raise self.validation_error(f"style='{style}' must be one of {self.STYLE_CHOICES!r}")

        return super().get_context_data(slots, **{
            'type': type,
            'name': name,
            'value': value,
            'style': style,
        })
        

@register.inline_component
class FormErrors(Component):
    def get_context_data(self, slots: dict[str, str], errors: ErrorList):
        return super().get_context_data(slots, **{
            'errors': errors,
        })


@register.inline_component
class FormField(Component):
    def get_context_data(self, slots: dict[str, str], field):
        return super().get_context_data(slots, **{
            'field': field,
        })


@register.component
class Form(Component):
    def get_context_data(
        self, 
        slots: dict[str, str],
        *,
        form: Form, 
        action: str = '', 
        method: str = 'post', 
        csrf_token: str = '', 
        csrf_exempt: bool = False
    ):
        if csrf_exempt is False and method == 'post' and csrf_token == '':
            raise self.validation_error(
                "csrf_token keyword argument is required when method is post and csrf_exempt is false"
            )
        
        return super().get_context_data(slots, **{
            'form': form,
            'action': action,
            'method': method,
            'csrf_token': csrf_token,
        })

HTML

{# app/templates/components/button.html #}
<button {% if type %} type="{{ type }}"{% endif %}{% if name %} name="{{ name }}"{% endif %}
    class="btn{% if style == "green" %} btn--green{% elif style == "red" %}btn--red{% endif %}">
    {{ value|default:slot }}
</button>
{# app/templates/components/form_errors.html #}
{% if errors %}
<div>
    {% for error in errors %}
    <div>{{ error }}</div>
    {% endfor %}
</div>
{% endif %}
{# app/templates/components/form_field.html #}
{% load component_tags %}
<div class="field">
    {% if field.label %}
        <label for="{{ field.id_for_label }}">{{ field.label }}</label>
    {% endif %}
    {% form_errors/ errors=field.errors %}
    <div>
        {{ field }}
    </div>
    {% if field.help_text %}
        <small>{{ field.help_text }}</small>
    {% endif %}
</div>
{# app/templates/components/form.html #}
{% load component_tags %}
<form action="{{ action }}" method="{{ method }}"{% if form.is_multipart %} enctype="multipart/form-data"{% endif %}>
    {% if csrf_token %}<input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">{% endif %}
    {% for field in form.hidden_fields %}{{ field }}{% endfor %}
    
    {{ slots.hidden_fields }}
        
    {% form_errors/ errors=form.non_field_errors %}
    
    {% if slots.visible_fields %}
        {{ slots.visible_fields }}
    {% else %}
        {% for field in form.visible_fields %}
            {% form_field/ field=field %}
        {% endfor %}
    {% endif %}
    
    {% if slots.buttons %}
        {{ slots.buttons }}
    {% else %}
        {% button/ value=_("Submit") %}
    {% endif %}
</form>

Usage

{% load slot_tags %}
{% load component_tags %}


<!-- inline use -->
{% form/ form=form csrf_token=csrf_token %}

<!-- block use -->
{% form form=form csrf_token=csrf_token %}

    <!-- override visible_fields slot in base template -->
    {% slot visible_fields %}
        {% form_field/ field=form.title %}
    {% /slot %}

    <!-- override buttons slot in base template -->
    {% slot buttons %}
        {% button %}Delete{% /button %}
    {% /slot %}
{% /form %}

Namespace

# nhsuk_components/templatetags/nhsuk_components.py
from django_slots.components import Library, Component

register = Library()


class NHSUKComponent(Component):
    namespace = 'nhsuk'


@register.component
class Button(NHSUKComponent):
    pass
{# nhsuk_components/templates/components/nhsuk/button.html #}
<button>{{ value|default:slot }}</button>

Usage

{% load nhsuk_components %}

{% nhsuk:button/ value="Save" %}

{% nhsuk:button %}
    <div>Save</div>
    <small>and add another</small>
{% /nhsuk:button %}

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

django_slots-0.2.5.tar.gz (6.5 kB view details)

Uploaded Source

Built Distribution

django_slots-0.2.5-py3-none-any.whl (6.2 kB view details)

Uploaded Python 3

File details

Details for the file django_slots-0.2.5.tar.gz.

File metadata

  • Download URL: django_slots-0.2.5.tar.gz
  • Upload date:
  • Size: 6.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.13 CPython/3.10.2 Darwin/21.0.1

File hashes

Hashes for django_slots-0.2.5.tar.gz
Algorithm Hash digest
SHA256 ecfc6c5f73e028687e26befb6c810e87392d48202459b4e689edd24d42750a29
MD5 435ef52055e6e7d177183b6a443692be
BLAKE2b-256 928dc03b4b9a53855eaf6bd57b2ac2039c04d13d286b807601031882dfffef6b

See more details on using hashes here.

File details

Details for the file django_slots-0.2.5-py3-none-any.whl.

File metadata

  • Download URL: django_slots-0.2.5-py3-none-any.whl
  • Upload date:
  • Size: 6.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.13 CPython/3.10.2 Darwin/21.0.1

File hashes

Hashes for django_slots-0.2.5-py3-none-any.whl
Algorithm Hash digest
SHA256 c41f48166d00364f1d8a0f753f0d7613e776855127f5e4142b5ea0046c35b0aa
MD5 bf2ae7aad70116e3d2114b17ef2c57d8
BLAKE2b-256 aaa92bfcb0fbffff8776efc8aaf527776b6a4a00114a1aad83a282d25476f03d

See more details on using hashes here.

Supported by

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