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>{{ slot }}</button>
Usage
{% load component_tags %}
{% 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,
filled_slots: list[str],
*,
type: str = 'submit',
name: str ='',
value: str = 'Submit',
style: str = 'green'
):
if value and DEFAULT_SLOT_NAME in filled_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 {
'type': type,
'name': name,
'value': value,
'style': style,
}
@register.inline_component
class FormErrors(Component):
def get_context_data(self, filled_slots: list[str], *, errors: ErrorList):
return {
'errors': errors,
}
@register.inline_component
class FormField(Component):
def get_context_data(self, filled_slots: list[str], *, field):
return {
'field': field,
}
@register.component
class Form(Component):
def get_context_data(
self,
filled_slots: list[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 {
'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 %}
Project details
Release history Release notifications | RSS feed
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.1.2.tar.gz
(6.1 kB
view details)
Built Distribution
File details
Details for the file django_slots-0.1.2.tar.gz
.
File metadata
- Download URL: django_slots-0.1.2.tar.gz
- Upload date:
- Size: 6.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.1.13 CPython/3.10.2 Darwin/21.0.1
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | bb16fb67432a1d1b9efc376165c03f25897dfd3b86b822b0383967666a8a944d |
|
MD5 | 3ef34c638352cb60cba8340ae6d18e30 |
|
BLAKE2b-256 | 678cb64f53ee91043f1655db3a223e9c22efc68d6d91cabac3ce910dd497dd66 |
File details
Details for the file django_slots-0.1.2-py3-none-any.whl
.
File metadata
- Download URL: django_slots-0.1.2-py3-none-any.whl
- Upload date:
- Size: 6.0 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
Algorithm | Hash digest | |
---|---|---|
SHA256 | c7c90bb4a1c70dfea082cd17a1f638d6e19da28044281ecf04b7e9add7c8c1ea |
|
MD5 | 76f2072e4badc295c78cf4e7b6cdd784 |
|
BLAKE2b-256 | bd297bc3e8d0efe21b5733d69f22a46f4547b7e2fd91d9fe156a4ad2399d6f88 |