Release notesΒ€
π¨π’ v0.110Β€
GeneralΒ€
π¨π’ BREAKING CHANGESΒ€
-
Installation changes:
- If your components include JS or CSS, you now must use the middleware and add django-components' URLs to your
urlpatterns(See "Adding support for JS and CSS")
- If your components include JS or CSS, you now must use the middleware and add django-components' URLs to your
-
Component typing signature changed from
to
-
If you rendered a component A with
Component.render()and then inserted that into another component B, now you must passrender_dependencies=Falseto component A:
FeatΒ€
- Intellisense and mypy validation for settings:
Instead of defining the COMPONENTS settings as a plain dict, you can use ComponentsSettings:
# settings.py
from django_components import ComponentsSettings
COMPONENTS = ComponentsSettings(
autodiscover=True,
...
)
- Use
get_component_dirs()andget_component_files()to get the same list of dirs / files that would be imported byautodiscover(), but without actually importing them.
RefactorΒ€
-
For advanced use cases, use can omit the middleware and instead manage component JS and CSS dependencies yourself with
render_dependencies -
The
ComponentRegistrysettingsRegistrySettingswere lowercased to align with the global settings: RegistrySettings.CONTEXT_BEHAVIOR->RegistrySettings.context_behaviorRegistrySettings.TAG_FORMATTER->RegistrySettings.tag_formatter
The old uppercase settings CONTEXT_BEHAVIOR and TAG_FORMATTER are deprecated and will be removed in v1.
-
The setting
reload_on_template_changewas renamed toreload_on_file_change. And now it properly triggers server reload when any file in the component dirs change. The old namereload_on_template_changeis deprecated and will be removed in v1. -
The setting
forbidden_static_fileswas renamed tostatic_files_forbiddento align withstatic_files_allowedThe old nameforbidden_static_filesis deprecated and will be removed in v1.
TagsΒ€
π¨π’ BREAKING CHANGESΒ€
-
{% component_dependencies %}tag was removed. Instead, use{% component_js_dependencies %}and{% component_css_dependencies %}-
The combined tag was removed to encourage the best practice of putting JS scripts at the end of
<body>, and CSS styles inside<head>.On the other hand, co-locating JS script and CSS styles can lead to a flash of unstyled content, as either JS scripts will block the rendering, or CSS will load too late.
-
-
The undocumented keyword arg
preloadof{% component_js_dependencies %}and{% component_css_dependencies %}tags was removed. This will be replaced with HTML fragment support.
FixΒ€
- Allow using forward slash (
/) when defining custom TagFormatter, e.g.{% MyComp %}..{% /MyComp %}.
RefactorΒ€
{% component_dependencies %}tags are now OPTIONAL - If your components use JS and CSS, but you don't use{% component_dependencies %}tags, the JS and CSS will now be, by default, inserted at the end of<body>and at the end of<head>respectively.
SlotsΒ€
FeatΒ€
- Fills can now be defined within loops (
{% for %}) or other tags (like{% with %}), or even other templates using{% include %}.
Following is now possible
{% component "table" %}
{% for slot_name in slots %}
{% fill name=slot_name %}
{% endfill %}
{% endfor %}
{% endcomponent %}
- If you need to access the data or the default content of a default fill, you can set the
namekwarg to"default".
Previously, a default fill would be defined simply by omitting the {% fill %} tags:
But in that case you could not access the slot data or the default content, like it's possible for named fills:
{% component "child" %}
{% fill name="header" data="data" %}
Hello {{ data.user.name }}
{% endfill %}
{% endcomponent %}
Now, you can specify default tag by using name="default":
{% component "child" %}
{% fill name="default" data="data" %}
Hello {{ data.user.name }}
{% endfill %}
{% endcomponent %}
- When inside
get_context_data()or other component methods, the default fill can now be accessed asComponent.input.slots["default"], e.g.:
class MyTable(Component):
def get_context_data(self, *args, **kwargs):
default_slot = self.input.slots["default"]
...
- You can now dynamically pass all slots to a child component. This is similar to passing all slots in Vue:
class MyTable(Component):
def get_context_data(self, *args, **kwargs):
return {
"slots": self.input.slots,
}
template: """
<div>
{% component "child" %}
{% for slot_name in slots %}
{% fill name=slot_name data="data" %}
{% slot name=slot_name ...data / %}
{% endfill %}
{% endfor %}
{% endcomponent %}
</div>
"""
FixΒ€
-
Slots defined with
{% fill %}tags are now properly accessible viaself.input.slotsinget_context_data() -
Do not raise error if multiple slots with same name are flagged as default
-
Slots can now be defined within loops (
{% for %}) or other tags (like{% with %}), or even other templates using{% include %}.
Previously, following would cause the kwarg name to be an empty string:
RefactorΒ€
- When you define multiple slots with the same name inside a template, you now have to set the
defaultandrequiredflags individually.
<div class="calendar-component">
<div class="header">
{% slot "image" default required %}Image here{% endslot %}
</div>
<div class="body">
{% slot "image" default required %}Image here{% endslot %}
</div>
</div>
This means you can also have multiple slots with the same name but different conditions.
E.g. in this example, we have a component that renders a user avatar - a small circular image with a profile picture of name initials.
If the component is given image_src or name_initials variables, the image slot is optional. But if neither of those are provided, you MUST fill the image slot.
<div class="avatar">
{% if image_src %}
{% slot "image" default %}
<img src="{{ image_src }}" />
{% endslot %}
{% elif name_initials %}
{% slot "image" default required %}
<div style="
border-radius: 25px;
width: 50px;
height: 50px;
background: blue;
">
{{ name_initials }}
</div>
{% endslot %}
{% else %}
{% slot "image" default required / %}
{% endif %}
</div>
- The slot fills that were passed to a component and which can be accessed as
Component.input.slotscan now be passed through the Django template, e.g. as inputs to other tags.
Internally, django-components handles slot fills as functions.
Previously, if you tried to pass a slot fill within a template, Django would try to call it as a function.
Now, something like this is possible:
class MyTable(Component):
def get_context_data(self, *args, **kwargs):
return {
"child_slot": self.input.slots["child_slot"],
}
template: """
<div>
{% component "child" content=child_slot / %}
</div>
"""
NOTE: Using {% slot %} and {% fill %} tags is still the preferred method, but the approach above may be necessary in some complex or edge cases.
- The
is_filledvariable (and the{{ component_vars.is_filled }}context variable) now returnsFalsewhen you try to access a slot name which has not been defined:
Before:
{{ component_vars.is_filled.header }} -> True
{{ component_vars.is_filled.footer }} -> False
{{ component_vars.is_filled.nonexist }} -> "" (empty string)
After:
{{ component_vars.is_filled.header }} -> True
{{ component_vars.is_filled.footer }} -> False
{{ component_vars.is_filled.nonexist }} -> False
-
Components no longer raise an error if there are extra slot fills
-
Components will raise error when a slot is doubly-filled.
E.g. if we have a component with a default slot:
Now there is two ways how we can target this slot: Either using name="default" or name="content".
In case you specify BOTH, the component will raise an error:
{% component "child" %}
{% fill slot="default" %}
Hello from default slot
{% endfill %}
{% fill slot="content" data="data" %}
Hello from content slot
{% endfill %}
{% endcomponent %}
π¨π’ v0.100Β€
BREAKING CHANGESΒ€
-
django_components.safer_staticfilesapp was removed. It is no longer needed. -
Installation changes:
- Instead of defining component directories in
STATICFILES_DIRS, set them toCOMPONENTS.dirs. -
You now must define
STATICFILES_FINDERS
- Instead of defining component directories in
FeatΒ€
- Beside the top-level
/componentsdirectory, you can now define also app-level components dirs, e.g.[app]/components(SeeCOMPONENTS.app_dirs).
RefactorΒ€
- When you call
as_view()on a component instance, that instance will be passed toView.as_view()
v0.97Β€
FixΒ€
- Fixed template caching. You can now also manually create cached templates with
cached_template()
RefactorΒ€
-
The previously undocumented
get_templatewas made private. -
In it's place, there's a new
get_template, which supersedesget_template_string(will be removed in v1). The newget_templateis the same asget_template_string, except it allows to return either a string or a Template instance. -
You now must use only one of
template,get_template,template_name, orget_template_name.
v0.96Β€
FeatΒ€
-
Run-time type validation for Python 3.11+ - If the
Componentclass is typed, e.g.Component[Args, Kwargs, ...], the args, kwargs, slots, and data are validated against the given types. (See Runtime input validation with types) -
Render hooks - Set
on_render_beforeandon_render_aftermethods onComponentto intercept or modify the template or context before rendering, or the rendered result afterwards. (See Component hooks) -
component_vars.is_filledcontext variable can be accessed from withinon_render_beforeandon_render_afterhooks asself.is_filled.my_slot
0.95Β€
FeatΒ€
- Added support for dynamic components, where the component name is passed as a variable. (See Dynamic components)
RefactorΒ€
- Changed
Component.inputto raiseRuntimeErrorif accessed outside of render context. Previously it returnedNoneif unset.
v0.94Β€
FeatΒ€
-
django_components now automatically configures Django to support multi-line tags. (See Multi-line tags)
-
New setting
reload_on_template_change. Set this toTrueto reload the dev server on changes to component template files. (See Reload dev server on component file changes)
v0.93Β€
FeatΒ€
-
Spread operator
...dictinside template tags. (See Spread operator) -
Use template tags inside string literals in component inputs. (See Use template tags inside component inputs)
-
Dynamic slots, fills and provides - The
nameargument for these can now be a variable, a template expression, or via spread operator -
Component library authors can now configure
CONTEXT_BEHAVIORandTAG_FORMATTERsettings independently from user settings.
π¨π’ v0.92Β€
BREAKING CHANGESΒ€
Componentclass is no longer a subclass ofView. To configure theViewclass, set theComponent.Viewnested class. HTTP methods likegetorpostcan still be defined directly onComponentclass, andComponent.as_view()internally callsComponent.View.as_view(). (See Modifying the View class)
FeatΒ€
-
The inputs (args, kwargs, slots, context, ...) that you pass to
Component.render()can be accessed from withinget_context_data,get_templateandget_template_nameviaself.input. (See Accessing data passed to the component) -
Typing:
Componentclass supports generics that specify types forComponent.render(See Adding type hints with Generics)
v0.90Β€
FeatΒ€
-
All tags (
component,slot,fill, ...) now support "self-closing" or "inline" form, where you can omit the closing tag: -
All tags now support the "dictionary key" or "aggregate" syntax (
kwarg:key=val): -
You can change how the components are written in the template with TagFormatter.
The default is
django_components.component_formatter:While
django_components.shorthand_component_formatterallows you to write components like so:
π¨π’ v0.85Β€
BREAKING CHANGESΒ€
-
Autodiscovery module resolution changed. Following undocumented behavior was removed:
-
Previously, autodiscovery also imported any
[app]/components.pyfiles, and usedSETTINGS_MODULEto search for component dirs.To migrate from:
-
[app]/components.py- Define each module inCOMPONENTS.librariessetting, or import each module inside theAppConfig.ready()hook in respectiveapps.pyfiles. -
SETTINGS_MODULE- Define component dirs usingSTATICFILES_DIRS
-
-
Previously, autodiscovery handled relative files in
STATICFILES_DIRS. To align with Django,STATICFILES_DIRSnow must be full paths (Django docs).
-
π¨π’ v0.81Β€
BREAKING CHANGESΒ€
- The order of arguments to
render_to_responsehas changed, to align with the (now public)rendermethod ofComponentclass.
FeatΒ€
-
Component.render()is public and documented -
Slots passed
render_to_responseandrendercan now be rendered also as functions.
v0.80Β€
FeatΒ€
- Vue-like provide/inject with the
{% provide %}tag andinject()method.
π¨π’ v0.79Β€
BREAKING CHANGESΒ€
- Default value for the
COMPONENTS.context_behaviorsetting was changes from"isolated"to"django". If you did not set this value explicitly before, this may be a breaking change. See the rationale for change here.
π¨π’ v0.77Β€
BREAKINGΒ€
-
The syntax for accessing default slot content has changed from
to
v0.74Β€
FeatΒ€
-
{% html_attrs %}tag for formatting data as HTML attributes -
prefix:key=valconstruct for passing dicts to components
π¨π’ v0.70Β€
BREAKING CHANGESΒ€
-
{% if_filled "my_slot" %}tags were replaced with{{ component_vars.is_filled.my_slot }}variables. -
Simplified settings -
slot_context_behaviorandcontext_behaviorwere merged. See the documentation for more details.
v0.67Β€
RefactorΒ€
- Changed the default way how context variables are resolved in slots. See the documentation for more details.
π¨π’ v0.50Β€
BREAKING CHANGESΒ€
-
{% component_block %}is now{% component %}, and{% component %}blocks need an ending{% endcomponent %}tag.The new
python manage.py upgradecomponentcommand can be used to upgrade a directory (use--pathargument to point to each dir) of templates that use components to the new syntax automatically.This change is done to simplify the API in anticipation of a 1.0 release of django_components. After 1.0 we intend to be stricter with big changes like this in point releases.
v0.34Β€
FeatΒ€
- Components as views, which allows you to handle requests and render responses from within a component. See the documentation for more details.
v0.28Β€
FeatΒ€
- 'implicit' slot filling and the
defaultoption forslottags.
v0.27Β€
FeatΒ€
- A second installable app
django_components.safer_staticfiles. It provides the same behavior asdjango.contrib.staticfilesbut with extra security guarantees (more info below in Security Notes).
π¨π’ v0.26Β€
BREAKING CHANGESΒ€
-
Changed the syntax for
{% slot %}tags. From now on, we separate defining a slot ({% slot %}) from filling a slot with content ({% fill %}). This means you will likely need to change a lot of slot tags to fill.We understand this is annoying, but it's the only way we can get support for nested slots that fill in other slots, which is a very nice feature to have access to. Hoping that this will feel worth it!
v0.22Β€
FeatΒ€
-
All files inside components subdirectores are autoimported to simplify setup.
An existing project might start to get
AlreadyRegisterederrors because of this. To solve this, either remove your custom loading of components, or set"autodiscover": Falseinsettings.COMPONENTS.
v0.17Β€
BREAKING CHANGESΒ€
-
Renamed
Component.contextandComponent.templatetoget_context_dataandget_template_name. The old methods still work, but emit a deprecation warning.This change was done to sync naming with Django's class based views, and make using django-components more familiar to Django users.
Component.contextandComponent.templatewill be removed when version 1.0 is released.