Skip to main content

Create advanced HTML components using Django Tags.

Project description

Test Status:
GitHub Workflow Status
Version Info:
PyPI PyPI - Downloads
Compatibility:
https://img.shields.io/pypi/pyversions/django-component-tags?style=flat-square&label=Python%20Versions PyPI - Django Version

Create advanced HTML components using Django Tags.

Description

Use Django Template Tags and write reusable html components.

Features

  • Class based template tags.

  • Template tag argument parser.

  • Declarative component attributes.

  • Extendable components.

  • Embedded slot components.

  • Media class (css/js) implementation (Django Form-Media class)

Extra

Libraries created with django-component-tags:

Requirements

Requires Django 2.2 or newer, tested against Python 3.7 and PyPy.

Quick Start

Install the library:

pip3 install django-component-tags

Update your settings.py:

INSTALLED_APPS = [
    ...
    'component_tags',
    ...
]

...

TEMPLATES = [
    {
        'OPTIONS': {
            'builtins': ['component_tags.template.builtins'], # slot component
        },
    },
]

...

Assuming that you already have an application called foo, lets create a new component tag:

# foo/templatetags/foo_tags.py
from component_tags import template

register = template.Library()

@register.tag
class Link(template.Component):
    href = template.Attribute(default='#')

    class Meta:
        template_name = 'tags/link.html'

Next, creating the component template:

# foo/templates/foo/tags/link.html

<a {{ attributes }}>
    {{ nodelist }}
</a>

Here we have a couple of variables inside a component template:

  • attributes: component template/class attributes (formatted).

  • nodelist: the content created between {% link %} and {% endlink %} will be rendered here.

Finally, you can use it as follows:

# foo/templates/foo/index.html
{% load foo_tags %}

{% link %}
    Link 1
{% endlink %}

Output:

# foo/templates/foo/index.html

<a href="#">
    Link 1
</a>

This is the simplest way to start, there is a lot of different settings that you can combine to create complex html components.

Considerations

Making multiple changes on html components and using cache interferes with the Media Class Library, which i believe its good on production. Django recommends to set up DummyCache on development environments:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
    }
}

Examples

Adding css/js scripts

Assuming that you already downloaded a css framework in your project like BootstrapCSS.

Lets create a component:

# foo/templatetags/foo_tags.py
from component_tags import template

register = template.Library()

@register.tag
class Link(template.Component):
    href = template.Attribute(default='#')

    class Meta:
        template_name = 'tags/link.html'
        css = {
            'all': ('css/bootstrap.min.css',)
        }
        js = [
            'js/bootstrap.bundle.min.js',
        ]

Rendering the component in the main template:

# foo/templates/foo/index.html
{% load foo_tags %}
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>---</title>
    <meta name="description" content="---">
    <meta name="author" content="---">
    {% components_css %}
</head>

<body>
{% link %}
    Link 1
{% endlink %}
{% components_js %}
</body>
</html>

Output:

# foo/templates/foo/index.html
{% load foo_tags %}
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>---</title>
    <meta name="description" content="---">
    <meta name="author" content="---">
    <link href="/static/css/bootstrap.min.css" type="text/css" media="all" rel="stylesheet">
</head>

<body>
<a class="btn btn-primary" href="#">
    Link 1
</a>
<script src="/static/js/bootstrap.bundle.min.js"></script>
</body>
</html>

Adding css classes

Lets create a html component using the bootstrap framework

# foo/templatetags/foo_tags.py
from component_tags import template

register = template.Library()

@register.tag
class Link(template.Component):
    class ColorChoices(template.AttributeChoices):
        primary = 'btn btn-primary'
        secondary = 'btn btn-secondary'
        success = 'btn btn-success'
        danger = 'btn btn-danger'
        warning = 'btn btn-warning'
        info = 'btn btn-info'

    color = template.Attribute(choices=TypeChoices, default=TypeChoices.submit, as_class=True)
    href = template.Attribute(default='#')

    class Meta:
        template_name = 'tags/link.html'
        css = {
            'all': ('css/bootstrap.min.css',)
        }
        js = [
            'js/bootstrap.bundle.min.js',
        ]

Rendering the component:

# foo/templates/foo/index.html
{% load foo_tags %}
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>---</title>
    <meta name="description" content="---">
    <meta name="author" content="---">
    {% components_css %}
</head>

<body>
{% link color="primary" class="foo-bar" %}
    Link 1
{% endlink %}

{% components_js %}
</body>
</html>

Also we added the class argument to the component tag, so even if the components strictly have class attributes, you will always have a flexible way to customize your components any time in different scenarios.

Output:

# foo/templates/foo/index.html
{% load foo_tags %}
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>---</title>
    <meta name="description" content="---">
    <meta name="author" content="---">
    <link href="/static/css/bootstrap.min.css" type="text/css" media="all" rel="stylesheet">
</head>

<body>
<a class="btn btn-primary foo-bar" href="#">
    Link 1
</a>
<script src="/static/js/bootstrap.bundle.min.js"></script>
</body>
</html>

Note that it was merged with all attribute classes previously declared.

Using slot components

Lets make another html component using the bootstrap framework, this one is going to be a Card component.

# foo/templatetags/foo_tags.py
from component_tags import template

register = template.Library()

@register.tag
class Card(template.Component):
    title = template.Attribute(required=True, as_context=True)

    class Meta:
        template_name = 'tags/card.html'

Create the component template:

# foo/templates/foo/tags/card.html

<div class="card" style="width: 18rem;">
  <img src="..." class="card-img-top" alt="...">
  <div class="card-body">
    <h5 class="card-title">{{ title }}</h5>
    <div class="card-text">
        {{ nodelist }}
    </div>
    {% if slot_footer %}
        <div class="card-footer">
            {{ slot_footer }}
        </div>
    {% endif %}
  </div>
</div>

Rendering the component:

# foo/templates/foo/index.html
{% load foo_tags %}

{% card title='foo' %}
    Some quick example text to build on the card title and make up the bulk of the card's content.
    {% slot 'footer' %}
        <a href="#" class="btn btn-primary">Go somewhere</a>
    {% endslot %}
{% endcard %}

Output:

# foo/templates/foo/index.html

<div class="card" style="width: 18rem;">
    <img src="..." class="card-img-top" alt="...">
    <div class="card-body">
        <h5 class="card-title">foo</h5>
        <div class="card-text">
            Some quick example text to build on the card title and make up the bulk of the card's content.
        </div>
        <div class="card-footer">
            <a href="#" class="btn btn-primary">Go somewhere</a>
        </div>
    </div>
</div>

Adding extra context

By default, all components used isolated context to work with. If you want to pass global context to the component tag it is required to use the with argument.

# foo/views.py
def foo(request, object_id=None):
    return render(request, 'foo/index.html', {
        'object_id': object_id
    })
# foo/templates/foo/index.html
{% load foo_tags %}

{% link color="primary" with id=object_id %}
    Link {{ id }}
{% endlink %}

Assuming that the request of the page will be something like http://localhost:8000/foo/1/, the output will be:

# foo/templates/foo/index.html

<a class="btn btn-primary" href="#">
    Link 1
</a>

Note

This project has been set up using PyScaffold 4.0rc2. For details and usage information on PyScaffold see https://pyscaffold.org/.

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_component_tags-0.0.6.1.tar.gz (36.8 kB view details)

Uploaded Source

Built Distribution

django_component_tags-0.0.6.1-py2.py3-none-any.whl (20.8 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file django_component_tags-0.0.6.1.tar.gz.

File metadata

  • Download URL: django_component_tags-0.0.6.1.tar.gz
  • Upload date:
  • Size: 36.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.1 importlib_metadata/4.6.1 pkginfo/1.7.1 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.61.2 CPython/3.9.5

File hashes

Hashes for django_component_tags-0.0.6.1.tar.gz
Algorithm Hash digest
SHA256 6d58fb7619408ff28b904c58b7adbd599d2c14b91b56477b3044f561596c24c8
MD5 188942437d3a2d1f9356170c661552bf
BLAKE2b-256 277222b9981b10a7252f82bd553a315917186ea8d5fce94ed9a6ac9e6fbfe5e7

See more details on using hashes here.

File details

Details for the file django_component_tags-0.0.6.1-py2.py3-none-any.whl.

File metadata

  • Download URL: django_component_tags-0.0.6.1-py2.py3-none-any.whl
  • Upload date:
  • Size: 20.8 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.1 importlib_metadata/4.6.1 pkginfo/1.7.1 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.61.2 CPython/3.9.5

File hashes

Hashes for django_component_tags-0.0.6.1-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 954648934baf8bfc1ddfcdd834e8e338f8c3c73e64853c9cf154c6ac19b030db
MD5 a6790b15e82863801e2f875c4c094f63
BLAKE2b-256 7eeaa88e70758ed42dbd2593c946b0c3693711cb243895d1e24262c43c817187

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