Django components that know how to render themselves.
Project description
Laces
Django components that know how to render themselves.
Working with objects that know how to render themselves as HTML elements is a common pattern found in complex Django applications (e.g. the Wagtail admin interface). This package provides tools enable and support working with such objects, also known as "components".
The APIs provided in the package have previously been discovered, developed and solidified in the Wagtail project. The purpose of this package is to make these tools available to other Django projects outside the Wagtail ecosystem.
Links
Supported versions
- Python >= 3.8
- Django >= 3.2
Installation
First, install with pip:
$ python -m pip install laces
Then, add to your installed apps:
# settings.py
INSTALLED_APPS = ["laces", ...]
That's it.
Usage
Creating components
The preferred way to create a component is to define a subclass of laces.components.Component
and specify a template_name
attribute on it.
The rendered template will then be used as the component's HTML representation:
# my_app/components.py
from laces.components import Component
class WelcomePanel(Component):
template_name = "my_app/panels/welcome.html"
my_welcome_panel = WelcomePanel()
{# my_app/templates/my_app/panels/welcome.html #}
<h1>Welcome to my app!</h1>
For simple cases that don't require a template, the render_html
method can be overridden instead:
# my_app/components.py
from django.utils.html import format_html
from laces.components import Component
class WelcomePanel(Component):
def render_html(self, parent_context):
return format_html("<h1>{}</h1>", "Welcome to my app!")
Passing context to the template
The get_context_data
method can be overridden to pass context variables to the template.
As with render_html
, this receives the context dictionary from the calling template.
# my_app/components.py
from laces.components import Component
class WelcomePanel(Component):
template_name = "my_app/panels/welcome.html"
def get_context_data(self, parent_context):
context = super().get_context_data(parent_context)
context["username"] = parent_context["request"].user.username
return context
{# my_app/templates/my_app/panels/welcome.html #}
<h1>Welcome to my app, {{ username }}!</h1>
Adding media definitions
Like Django form widgets, components can specify associated JavaScript and CSS resources using either an inner Media
class or a dynamic media
property.
# my_app/components.py
from laces.components import Component
class WelcomePanel(Component):
template_name = "my_app/panels/welcome.html"
class Media:
css = {"all": ("my_app/css/welcome-panel.css",)}
Using components in other templates
The laces
tag library provides a {% component %}
tag for including components on a template.
This takes care of passing context variables from the calling template to the component (which would not be the case for a basic {{ ... }}
variable tag).
For example, given the view passes an instance of WelcomePanel
to the context of my_app/welcome.html
.
# my_app/views.py
from django.shortcuts import render
from my_app.components import WelcomePanel
def welcome_page(request):
panel = (WelcomePanel(),)
return render(
request,
"my_app/welcome.html",
{
"panel": panel,
},
)
The template my_app/templates/my_app/welcome.html
could render the panel as follows:
{# my_app/templates/my_app/welcome.html #}
{% load laces %}
{% component panel %}
You can pass additional context variables to the component using the keyword with
:
{% component panel with username=request.user.username %}
To render the component with only the variables provided (and no others from the calling template's context), use only
:
{% component panel with username=request.user.username only %}
To store the component's rendered output in a variable rather than outputting it immediately, use as
followed by the variable name:
{% component panel as panel_html %}
{{ panel_html }}
Note that it is your template's responsibility to output any media declarations defined on the components.
This can be done by constructing a media object for the whole page within the view, passing this to the template, and outputting it via media.js
and media.css
.
# my_app/views.py
from django.forms import Media
from django.shortcuts import render
from my_app.components import WelcomePanel
def welcome_page(request):
panels = [
WelcomePanel(),
]
media = Media()
for panel in panels:
media += panel.media
render(
request,
"my_app/welcome.html",
{
"panels": panels,
"media": media,
},
)
{# my_app/templates/my_app/welcome.html #}
{% load laces %}
<head>
{{ media.js }}
{{ media.css }}
<head>
<body>
{% for panel in panels %}
{% component panel %}
{% endfor %}
</body>
Contributing
Install
To make changes to this project, first clone this repository:
$ git clone https://github.com/tbrlpld/laces.git
$ cd laces
With your preferred virtualenv activated, install testing dependencies:
Using pip
$ python -m pip install --upgrade pip>=21.3
$ python -m pip install -e '.[testing]' -U
Using flit
$ python -m pip install flit
$ flit install
pre-commit
Note that this project uses pre-commit. It is included in the project testing requirements. To set up locally:
# go to the project directory
$ cd laces
# initialize pre-commit
$ pre-commit install
# Optional, run all checks once for this, then the checks will run only on the changed files
$ git ls-files --others --cached --exclude-standard | xargs pre-commit run --files
How to run tests
Now you can run all tests like so:
$ tox
Or, you can run them for a specific environment:
$ tox -e python3.11-django4.2-wagtail5.1
Or, run only a specific test:
$ tox -e python3.11-django4.2-wagtail5.1-sqlite laces.tests.test_file.TestClass.test_method
To run the test app interactively, use:
$ tox -e interactive
You can now visit http://localhost:8020/
.
Python version management
Tox will attempt to find installed Python versions on your machine.
If you use pyenv
to manage multiple versions, you can tell tox
to use those versions.
This working, is depended on virtualenv-pyenv
(note: this is not pyenv-virtualenv
) which is part of the CI dependencies (just like tox
itself is).
To enable the use, you want to set the environment variable VIRTUALENV_DISCOVERY=pyenv
.
Publishing
This project uses the Trusted Publisher model for PyPI releases. This means that publishing is done through GitHub Actions when a new release is created on GitHub.
Before publishing a new release, make sure to update the changelog in CHANGELOG.md
and the version number in laces/__init__.py
.
To manually test publishing the package, you can use flit
.
Be sure to configure the testpypi
repository in your ~/.pypirc
file according to the Flit documentation.
If your PyPI account is using 2FA, you'll need to create a PyPI API token and use that as your password and __token__
as the username.
When you're ready to test the publishing, run:
$ flit build
$ flit publish --repository testpypi
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.