What's the best way to handle valueless attributes in Django templates?
I'm looking for a cleaner way to conditionally add valueless HTML attributes, like disabled
, in a Django template.
For example, in the code snippet below, the {% if %}
tag is embedded directly inside the <button>
tag, which I find makes the code harder to read.
<button type="submit"
id="prev-page-btn"
class="btn btn-secondary w-50"
name="prev-page-btn"
{% if not page_obj.has_previous %}disabled{% endif %}>
Previous
</button>
Is there a more elegant solution for this? I'd like to avoid duplicating the entire <button>
block just to control the presence of the disabled
attribute.
Instead of putting the {% if %} logic directly in the tag, assign it to a context variable or use the {% with %} tag.
Like:
{% with 'disabled' if not page_obj.has_previous else '' as disabled_attr %}
<button type="submit"
id="prev-page-btn"
class="btn btn-secondary w-50"
name="prev-page-btn"
{{ disabled_attr }}>
Previous
</button>
{% endwith %}
What might help here is a custom template tag [Django-doc], like:
# some_app/templatetags/htmlattr.py
from django.forms.utils import flatattr
from django import template
register = template.Library()
@register.simple_tag(name='html_attributes')
def html_attributes(**kwargs):
return flatatt(kwargs)
then we can load this template tag in the template, and use it accordingly:
{% load htmlattr %}
{% with not page_obj.has_previous as no_previous %}
<button type="submit"
id="prev-page-btn"
class="btn btn-secondary w-50"
name="prev-page-btn"
{% html_attributes disabled=no_previous %}>
Previous
</button>
{% endwith %}
Our html_attributes
allows to work with key-values. If the value is False
or None
, it will not be included. If the value is a non-boolean, it will be passed as the value of the HTML attribute, so:
<tag {% html_attributes foo='bar' qux=False bla=True %}>
will be encoded in HTML as:
<tag foo="bar" bla>
We thus can replace the above with:
{% with not page_obj.has_previous as no_previous %}
<button {% html_attributes type='submit' id='prev-page-btn' class='btn btn-secondary w-50' name='prev-page-btn' disabled=no_previous %}>
Previous
</button>
{% endwith %}
Django uses this the flatatt
internally to format HTML attributes for wigets of a form.