diff --git a/0.112/404.html b/0.112/404.html new file mode 100644 index 00000000..a7816800 --- /dev/null +++ b/0.112/404.html @@ -0,0 +1 @@ +
Installation changes:
urlpatterns
(See "Adding support for JS and CSS")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 pass render_dependencies=False
to component A:
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,
+ ...
+)
+
get_component_dirs()
and get_component_files()
to get the same list of dirs / files that would be imported by autodiscover()
, but without actually importing them.For advanced use cases, use can omit the middleware and instead manage component JS and CSS dependencies yourself with render_dependencies
The ComponentRegistry
settings RegistrySettings
were lowercased to align with the global settings:
RegistrySettings.CONTEXT_BEHAVIOR
-> RegistrySettings.context_behavior
RegistrySettings.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_change
was renamed to reload_on_file_change
. And now it properly triggers server reload when any file in the component dirs change. The old name reload_on_template_change
is deprecated and will be removed in v1.
The setting forbidden_static_files
was renamed to static_files_forbidden
to align with static_files_allowed
The old name forbidden_static_files
is deprecated and will be removed in v1.
{% 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 preload
of {% component_js_dependencies %}
and {% component_css_dependencies %}
tags was removed. This will be replaced with HTML fragment support.
/
) when defining custom TagFormatter, e.g. {% MyComp %}..{% /MyComp %}
.{% 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.{% 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 %}
+
name
kwarg 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 %}
+
get_context_data()
or other component methods, the default fill can now be accessed as Component.input.slots["default"]
, e.g.:class MyTable(Component):
+ def get_context_data(self, *args, **kwargs):
+ default_slot = self.input.slots["default"]
+ ...
+
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>
+ """
+
Slots defined with {% fill %}
tags are now properly accessible via self.input.slots
in get_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:
default
and required
flags 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>
+
Component.input.slots
can 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.
is_filled
variable (and the {{ component_vars.is_filled }}
context variable) now returns False
when 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 %}
+
django_components.safer_staticfiles
app was removed. It is no longer needed.
Installation changes:
STATICFILES_DIRS
, set them to COMPONENTS.dirs
.You now must define STATICFILES_FINDERS
/components
directory, you can now define also app-level components dirs, e.g. [app]/components
(See COMPONENTS.app_dirs
).as_view()
on a component instance, that instance will be passed to View.as_view()
cached_template()
The previously undocumented get_template
was made private.
In it's place, there's a new get_template
, which supersedes get_template_string
(will be removed in v1). The new get_template
is the same as get_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
, or get_template_name
.
Run-time type validation for Python 3.11+ - If the Component
class 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_before
and on_render_after
methods on Component
to intercept or modify the template or context before rendering, or the rendered result afterwards. (See Component hooks)
component_vars.is_filled
context variable can be accessed from within on_render_before
and on_render_after
hooks as self.is_filled.my_slot
Component.input
to raise RuntimeError
if accessed outside of render context. Previously it returned None
if unset.django_components now automatically configures Django to support multi-line tags. (See Multi-line tags)
New setting reload_on_template_change
. Set this to True
to reload the dev server on changes to component template files. (See Reload dev server on component file changes)
Spread operator ...dict
inside 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 name
argument for these can now be a variable, a template expression, or via spread operator
Component library authors can now configure CONTEXT_BEHAVIOR
and TAG_FORMATTER
settings independently from user settings.
Component
class is no longer a subclass of View
. To configure the View
class, set the Component.View
nested class. HTTP methods like get
or post
can still be defined directly on Component
class, and Component.as_view()
internally calls Component.View.as_view()
. (See Modifying the View class)The inputs (args, kwargs, slots, context, ...) that you pass to Component.render()
can be accessed from within get_context_data
, get_template
and get_template_name
via self.input
. (See Accessing data passed to the component)
Typing: Component
class supports generics that specify types for Component.render
(See Adding type hints with Generics)
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_formatter
allows you to write components like so:
Autodiscovery module resolution changed. Following undocumented behavior was removed:
Previously, autodiscovery also imported any [app]/components.py
files, and used SETTINGS_MODULE
to search for component dirs.
To migrate from:
[app]/components.py
- Define each module in COMPONENTS.libraries
setting, or import each module inside the AppConfig.ready()
hook in respective apps.py
files.
SETTINGS_MODULE
- Define component dirs using STATICFILES_DIRS
Previously, autodiscovery handled relative files in STATICFILES_DIRS
. To align with Django, STATICFILES_DIRS
now must be full paths (Django docs).
render_to_response
has changed, to align with the (now public) render
method of Component
class.Component.render()
is public and documented
Slots passed render_to_response
and render
can now be rendered also as functions.
{% provide %}
tag and inject()
method.COMPONENTS.context_behavior
setting 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.The syntax for accessing default slot content has changed from
to
{% html_attrs %}
tag for formatting data as HTML attributes
prefix:key=val
construct for passing dicts to components
{% if_filled "my_slot" %}
tags were replaced with {{ component_vars.is_filled.my_slot }}
variables.
Simplified settings - slot_context_behavior
and context_behavior
were merged. See the documentation for more details.
{% component_block %}
is now {% component %}
, and {% component %}
blocks need an ending {% endcomponent %}
tag.
The new python manage.py upgradecomponent
command can be used to upgrade a directory (use --path
argument 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.
default
option for slot
tags.django_components.safer_staticfiles
. It provides the same behavior as django.contrib.staticfiles
but with extra security guarantees (more info below in Security Notes).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!
All files inside components subdirectores are autoimported to simplify setup.
An existing project might start to get AlreadyRegistered
errors because of this. To solve this, either remove your custom loading of components, or set "autodiscover": False
in settings.COMPONENTS
.
Renamed Component.context
and Component.template
to get_context_data
and get_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.context
and Component.template
will be removed when version 1.0 is released.
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
Examples of behavior that contributes to creating a positive environment include:
Examples of unacceptable behavior by participants include:
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at emil@emilstenstrom.se. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq