Args class-attribute
¤
Optional typing for positional arguments passed to the component.
If set and not None
, then the args
parameter of the data methods (get_template_data()
, get_js_data()
, get_css_data()
) will be the instance of this class:
from typing import NamedTuple
from django_components import Component
class Table(Component):
class Args(NamedTuple):
color: str
size: int
def get_template_data(self, args: Args, kwargs, slots, context):
assert isinstance(args, Table.Args)
return {
"color": args.color,
"size": args.size,
}
The constructor of this class MUST accept positional arguments:
As such, a good starting point is to set this field to a subclass of NamedTuple
.
Use Args
to:
get_template_data()
.You can also use Args
to validate the positional arguments for Component.render()
:
Table.render(
args=Table.Args(color="red", size=10),
)
Read more on Typing and validation.
Cache class-attribute
¤
The fields of this class are used to configure the component caching.
Read more about Component caching.
Example:
from django_components import Component
class MyComponent(Component):
class Cache:
enabled = True
ttl = 60 * 60 * 24 # 1 day
cache_name = "my_cache"
CssData class-attribute
¤
Optional typing for the data to be returned from get_css_data()
.
If set and not None
, then this class will be instantiated with the dictionary returned from get_css_data()
to validate the data.
The constructor of this class MUST accept keyword arguments:
You can also return an instance of CssData
directly from get_css_data()
to get type hints:
from typing import NamedTuple
from django_components import Component
class Table(Component):
class CssData(NamedTuple):
color: str
size: int
def get_css_data(self, args, kwargs, slots, context):
return Table.CssData(
color=kwargs["color"],
size=kwargs["size"],
)
A good starting point is to set this field to a subclass of NamedTuple
or a dataclass.
Use CssData
to:
get_css_data()
at runtime.Read more on Typing and validation.
Info
If you use a custom class for CssData
, this class needs to be convertable to a dictionary.
You can implement either:
_asdict()
method
class MyClass:
def __init__(self):
self.x = 1
self.y = 2
def _asdict(self):
return {'x': self.x, 'y': self.y}
Or make the class dict-like with __iter__()
and __getitem__()
class MyClass:
def __init__(self):
self.x = 1
self.y = 2
def __iter__(self):
return iter([('x', self.x), ('y', self.y)])
def __getitem__(self, key):
return getattr(self, key)
Defaults class-attribute
¤
The fields of this class are used to set default values for the component's kwargs.
Read more about Component defaults.
Example:
from django_components import Component, Default
class MyComponent(Component):
class Defaults:
position = "left"
selected_items = Default(lambda: [1, 2, 3])
JsData class-attribute
¤
Optional typing for the data to be returned from get_js_data()
.
If set and not None
, then this class will be instantiated with the dictionary returned from get_js_data()
to validate the data.
The constructor of this class MUST accept keyword arguments:
You can also return an instance of JsData
directly from get_js_data()
to get type hints:
from typing import NamedTuple
from django_components import Component
class Table(Component):
class JsData(NamedTuple):
color: str
size: int
def get_js_data(self, args, kwargs, slots, context):
return Table.JsData(
color=kwargs["color"],
size=kwargs["size"],
)
A good starting point is to set this field to a subclass of NamedTuple
or a dataclass.
Use JsData
to:
get_js_data()
at runtime.Read more on Typing and validation.
Info
If you use a custom class for JsData
, this class needs to be convertable to a dictionary.
You can implement either:
_asdict()
method
class MyClass:
def __init__(self):
self.x = 1
self.y = 2
def _asdict(self):
return {'x': self.x, 'y': self.y}
Or make the class dict-like with __iter__()
and __getitem__()
class MyClass:
def __init__(self):
self.x = 1
self.y = 2
def __iter__(self):
return iter([('x', self.x), ('y', self.y)])
def __getitem__(self, key):
return getattr(self, key)
Kwargs class-attribute
¤
Optional typing for keyword arguments passed to the component.
If set and not None
, then the kwargs
parameter of the data methods (get_template_data()
, get_js_data()
, get_css_data()
) will be the instance of this class:
from typing import NamedTuple
from django_components import Component
class Table(Component):
class Kwargs(NamedTuple):
color: str
size: int
def get_template_data(self, args, kwargs: Kwargs, slots, context):
assert isinstance(kwargs, Table.Kwargs)
return {
"color": kwargs.color,
"size": kwargs.size,
}
The constructor of this class MUST accept keyword arguments:
As such, a good starting point is to set this field to a subclass of NamedTuple
or a dataclass.
Use Kwargs
to:
get_template_data()
.You can also use Kwargs
to validate the keyword arguments for Component.render()
:
Table.render(
kwargs=Table.Kwargs(color="red", size=10),
)
Read more on Typing and validation.
Media class-attribute
¤
Defines JS and CSS media files associated with this component.
This Media
class behaves similarly to Django's Media class:
media_class.render_js()
or media_class.render_css()
.http
, https
, or /
is considered a URL, skipping the static file resolution. This path is still rendered to HTML with media_class.render_js()
or media_class.render_css()
.SafeString
(with __html__
method) is considered an already-formatted HTML tag, skipping both static file resolution and rendering with media_class.render_js()
or media_class.render_css()
.extend
to configure whether to inherit JS / CSS from parent components. See Media inheritance.However, there's a few differences from Django's Media class:
ComponentMediaInput
).str
, bytes
, Path
, SafeString
, or a function (See ComponentMediaInputPath
).Example:
class MyTable(Component):
class Media:
js = [
"path/to/script.js",
"https://unpkg.com/alpinejs@3.14.7/dist/cdn.min.js", # AlpineJS
]
css = {
"all": [
"path/to/style.css",
"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css", # TailwindCSS
],
"print": ["path/to/style2.css"],
}
Slots class-attribute
¤
Optional typing for slots passed to the component.
If set and not None
, then the slots
parameter of the data methods (get_template_data()
, get_js_data()
, get_css_data()
) will be the instance of this class:
from typing import NamedTuple
from django_components import Component, Slot, SlotInput
class Table(Component):
class Slots(NamedTuple):
header: SlotInput
footer: Slot
def get_template_data(self, args, kwargs, slots: Slots, context):
assert isinstance(slots, Table.Slots)
return {
"header": slots.header,
"footer": slots.footer,
}
The constructor of this class MUST accept keyword arguments:
As such, a good starting point is to set this field to a subclass of NamedTuple
or a dataclass.
Use Slots
to:
get_template_data()
.You can also use Slots
to validate the slots for Component.render()
:
Table.render(
slots=Table.Slots(
header="HELLO IM HEADER",
footer=Slot(lambda ctx: ...),
),
)
Read more on Typing and validation.
Info
Components can receive slots as strings, functions, or instances of Slot
.
Internally these are all normalized to instances of Slot
.
Therefore, the slots
dictionary available in data methods (like get_template_data()
) will always be a dictionary of Slot
instances.
To correctly type this dictionary, you should set the fields of Slots
to Slot
or SlotInput
:
SlotInput
is a union of Slot
, string, and function types.
TemplateData class-attribute
¤
Optional typing for the data to be returned from get_template_data()
.
If set and not None
, then this class will be instantiated with the dictionary returned from get_template_data()
to validate the data.
The constructor of this class MUST accept keyword arguments:
TemplateData(**template_data)
You can also return an instance of TemplateData
directly from get_template_data()
to get type hints:
from typing import NamedTuple
from django_components import Component
class Table(Component):
class TemplateData(NamedTuple):
color: str
size: int
def get_template_data(self, args, kwargs, slots, context):
return Table.TemplateData(
color=kwargs["color"],
size=kwargs["size"],
)
A good starting point is to set this field to a subclass of NamedTuple
or a dataclass.
Use TemplateData
to:
get_template_data()
at runtime.Read more on Typing and validation.
Info
If you use a custom class for TemplateData
, this class needs to be convertable to a dictionary.
You can implement either:
_asdict()
method
class MyClass:
def __init__(self):
self.x = 1
self.y = 2
def _asdict(self):
return {'x': self.x, 'y': self.y}
Or make the class dict-like with __iter__()
and __getitem__()
class MyClass:
def __init__(self):
self.x = 1
self.y = 2
def __iter__(self):
return iter([('x', self.x), ('y', self.y)])
def __getitem__(self, key):
return getattr(self, key)
View class-attribute
¤
The fields of this class are used to configure the component views and URLs.
This class is a subclass of django.views.View
. The Component
instance is available via self.component
.
Override the methods of this class to define the behavior of the component.
Read more about Component views and URLs.
Example:
class MyComponent(Component):
class View:
def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
return HttpResponse("Hello, world!")
args instance-attribute
¤
Positional arguments passed to the component.
This is part of the Render API.
args
has the same behavior as the args
argument of Component.get_template_data()
:
Component.Args
class, then the args
property will return an instance of that Args
class.args
will be a plain list.Example:
With Args
class:
from django_components import Component
class Table(Component):
class Args(NamedTuple):
page: int
per_page: int
def on_render_before(self, context: Context, template: Optional[Template]) -> None:
assert self.args.page == 123
assert self.args.per_page == 10
rendered = Table.render(
args=[123, 10],
)
Without Args
class:
from django_components import Component
class Table(Component):
def on_render_before(self, context: Context, template: Optional[Template]) -> None:
assert self.args[0] == 123
assert self.args[1] == 10
class_id class-attribute
¤
Unique ID of the component class, e.g. MyComponent_ab01f2
.
This is derived from the component class' module import path, e.g. path.to.my.MyComponent
.
context instance-attribute
¤
The context
argument as passed to Component.get_template_data()
.
This is Django's Context with which the component template is rendered.
If the root component or template was rendered with RequestContext
then this will be an instance of RequestContext
.
Whether the context variables defined in context
are available to the template depends on the context behavior mode:
In "django"
context behavior mode, the template will have access to the keys of this context.
In "isolated"
context behavior mode, the template will NOT have access to this context, and data MUST be passed via component's args and kwargs.
context_processors_data property
¤
context_processors_data: Dict
Retrieve data injected by context_processors
.
This data is also available from within the component's template, without having to return this data from get_template_data()
.
In regular Django templates, you need to use RequestContext
to apply context processors.
In Components, the context processors are applied to components either when:
RequestContext
(Regular Django behavior)Context
(or none), but the request
kwarg of Component.render()
is set.See Component.request
on how the request
(HTTPRequest) object is passed to and within the components.
NOTE: This dictionary is generated dynamically, so any changes to it will not be persisted.
Example:
class MyComponent(Component):
def get_template_data(self, args, kwargs, slots, context):
user = self.context_processors_data['user']
return {
'is_logged_in': user.is_authenticated,
}
css class-attribute
instance-attribute
¤
Main CSS associated with this component inlined as string.
Example:
class MyComponent(Component):
css = """
.my-class {
color: red;
}
"""
Syntax highlighting
When using the inlined template, you can enable syntax highlighting with django_components.types.css
.
Learn more about syntax highlighting.
from django_components import Component, types
class MyComponent(Component):
css: types.css = '''
.my-class {
color: red;
}
'''
css_file class-attribute
¤
Main CSS associated with this component as file path.
The filepath must be either:
COMPONENTS.dirs
or COMPONENTS.app_dirs
(e.g. <root>/components/
).STATICFILES_DIRS
setting (e.g. <root>/static/
).When you create a Component class with css_file
, these will happen:
Component.css
.Example:
path/to/style.css.my-class {
color: red;
}
path/to/component.py
class MyComponent(Component):
css_file = "path/to/style.css"
print(MyComponent.css)
# Output:
# .my-class {
# color: red;
# };
debug_highlight instance-attribute
¤
deps_strategy instance-attribute
¤
Dependencies strategy defines how to handle JS and CSS dependencies of this and child components.
Read more about Dependencies rendering.
This is part of the Render API.
There are six strategies:
"document"
(default)
<head>
and <body>
tags."fragment"
"simple"
<head>
and <body>
tags."prepend"
"append"
"ignore"
render_dependencies()
.
do_not_call_in_templates class-attribute
¤
do_not_call_in_templates: bool = True
Django special property to prevent calling the instance as a function inside Django templates.
Read more about Django's do_not_call_in_templates
.
id instance-attribute
¤
This ID is unique for every time a Component.render()
(or equivalent) is called (AKA "render ID").
This is useful for logging or debugging.
The ID is a 7-letter alphanumeric string in the format cXXXXXX
, where XXXXXX
is a random string of 6 alphanumeric characters (case-sensitive).
E.g. c1A2b3c
.
A single render ID has a chance of collision 1 in 57 billion. However, due to birthday paradox, the chance of collision increases to 1% when approaching ~33K render IDs.
Thus, there is currently a soft-cap of ~30K components rendered on a single page.
If you need to expand this limit, please open an issue on GitHub.
Example:
class MyComponent(Component):
def get_template_data(self, args, kwargs, slots, context):
print(f"Rendering '{self.id}'")
MyComponent.render()
# Rendering 'ab3c4d'
input instance-attribute
¤
Deprecated. Will be removed in v1.
Input holds the data that were passed to the current component at render time.
This includes:
args
- List of positional argumentskwargs
- Dictionary of keyword argumentsslots
- Dictionary of slots. Values are normalized to Slot
instancescontext
- Context
object that should be used to render the componentComponent.render()
like deps_strategy
Example:
class Table(Component):
def get_template_data(self, args, kwargs, slots, context):
# Access component's inputs, slots and context
assert self.args == [123, "str"]
assert self.kwargs == {"variable": "test", "another": 1}
footer_slot = self.slots["footer"]
some_var = self.input.context["some_var"]
rendered = TestComponent.render(
kwargs={"variable": "test", "another": 1},
args=[123, "str"],
slots={"footer": "MY_SLOT"},
)
is_filled instance-attribute
¤
Deprecated. Will be removed in v1. Use Component.slots
instead. Note that Component.slots
no longer escapes the slot names.
Dictionary describing which slots have or have not been filled.
This attribute is available for use only within:
You can also access this variable from within the template as
{{ component_vars.is_filled.slot_name }}
js class-attribute
instance-attribute
¤
Main JS associated with this component inlined as string.
Warning
Only one of js
or js_file
must be defined.
Example:
class MyComponent(Component):
js = "console.log('Hello, World!');"
Syntax highlighting
When using the inlined template, you can enable syntax highlighting with django_components.types.js
.
Learn more about syntax highlighting.
from django_components import Component, types
class MyComponent(Component):
js: types.js = '''
console.log('Hello, World!');
'''
js_file class-attribute
¤
Main JS associated with this component as file path.
The filepath must be either:
COMPONENTS.dirs
or COMPONENTS.app_dirs
(e.g. <root>/components/
).STATICFILES_DIRS
setting (e.g. <root>/static/
).When you create a Component class with js_file
, these will happen:
Component.js
.Warning
Only one of js
or js_file
must be defined.
Example:
path/to/script.jsconsole.log('Hello, World!');
path/to/component.py
class MyComponent(Component):
js_file = "path/to/script.js"
print(MyComponent.js)
# Output: console.log('Hello, World!');
kwargs instance-attribute
¤
Keyword arguments passed to the component.
This is part of the Render API.
kwargs
has the same behavior as the kwargs
argument of Component.get_template_data()
:
Component.Kwargs
class, then the kwargs
property will return an instance of that Kwargs
class.kwargs
will be a plain dict.Example:
With Kwargs
class:
from django_components import Component
class Table(Component):
class Kwargs(NamedTuple):
page: int
per_page: int
def on_render_before(self, context: Context, template: Optional[Template]) -> None:
assert self.kwargs.page == 123
assert self.kwargs.per_page == 10
rendered = Table.render(
kwargs={
"page": 123,
"per_page": 10,
},
)
Without Kwargs
class:
from django_components import Component
class Table(Component):
def on_render_before(self, context: Context, template: Optional[Template]) -> None:
assert self.kwargs["page"] == 123
assert self.kwargs["per_page"] == 10
media class-attribute
instance-attribute
¤
Normalized definition of JS and CSS media files associated with this component. None
if Component.Media
is not defined.
This field is generated from Component.media_class
.
Read more on Accessing component's Media JS / CSS.
Example:
class MyComponent(Component):
class Media:
js = "path/to/script.js"
css = "path/to/style.css"
print(MyComponent.media)
# Output:
# <script src="/static/path/to/script.js"></script>
# <link href="/static/path/to/style.css" media="all" rel="stylesheet">
media_class class-attribute
¤
media_class: Type[Media] = Media
Set the Media class that will be instantiated with the JS and CSS media files from Component.Media
.
This is useful when you want to customize the behavior of the media files, like customizing how the JS or CSS files are rendered into <script>
or <link>
HTML tags.
Read more in Media class.
Example:
class MyTable(Component):
class Media:
js = "path/to/script.js"
css = "path/to/style.css"
media_class = MyMediaClass
name instance-attribute
¤
The name of the component.
If the component was registered, this will be the name under which the component was registered in the ComponentRegistry
.
Otherwise, this will be the name of the class.
Example:
@register("my_component")
class RegisteredComponent(Component):
def get_template_data(self, args, kwargs, slots, context):
return {
"name": self.name, # "my_component"
}
class UnregisteredComponent(Component):
def get_template_data(self, args, kwargs, slots, context):
return {
"name": self.name, # "UnregisteredComponent"
}
node instance-attribute
¤
The ComponentNode
instance that was used to render the component.
This will be set only if the component was rendered with the {% component %}
tag.
Accessing the ComponentNode
is mostly useful for extensions, which can modify their behaviour based on the source of the Component.
class MyComponent(Component):
def get_template_data(self, context, template):
if self.node is not None:
assert self.node.name == "my_component"
For example, if MyComponent
was used in another component - that is, with a {% component "my_component" %}
tag in a template that belongs to another component - then you can use self.node.template_component
to access the owner Component
class.
class Parent(Component):
template: types.django_html = '''
<div>
{% component "my_component" / %}
</div>
'''
@register("my_component")
class MyComponent(Component):
def get_template_data(self, context, template):
if self.node is not None:
assert self.node.template_component == Parent
Info
Component.node
is None
if the component is created by Component.render()
(but you can pass in the node
kwarg yourself).
outer_context instance-attribute
¤
When a component is rendered with the {% component %}
tag, this is the Django's Context
object that was used just outside of the component.
{% with abc=123 %}
{{ abc }} {# <--- This is in outer context #}
{% component "my_component" / %}
{% endwith %}
This is relevant when your components are isolated, for example when using the "isolated" context behavior mode or when using the only
flag.
When components are isolated, each component has its own instance of Context, so outer_context
is different from the context
argument.
raw_args instance-attribute
¤
Positional arguments passed to the component.
This is part of the Render API.
Unlike Component.args
, this attribute is not typed and will remain as plain list even if you define the Component.Args
class.
Example:
from django_components import Component
class Table(Component):
def on_render_before(self, context: Context, template: Optional[Template]) -> None:
assert self.raw_args[0] == 123
assert self.raw_args[1] == 10
raw_kwargs instance-attribute
¤
Keyword arguments passed to the component.
This is part of the Render API.
Unlike Component.kwargs
, this attribute is not typed and will remain as plain dict even if you define the Component.Kwargs
class.
Example:
from django_components import Component
class Table(Component):
def on_render_before(self, context: Context, template: Optional[Template]) -> None:
assert self.raw_kwargs["page"] == 123
assert self.raw_kwargs["per_page"] == 10
raw_slots instance-attribute
¤
Slots passed to the component.
This is part of the Render API.
Unlike Component.slots
, this attribute is not typed and will remain as plain dict even if you define the Component.Slots
class.
Example:
from django_components import Component
class Table(Component):
def on_render_before(self, context: Context, template: Optional[Template]) -> None:
assert self.raw_slots["header"] == "MY_HEADER"
assert self.raw_slots["footer"] == "FOOTER: " + ctx.data["user_id"]
registered_name instance-attribute
¤
If the component was rendered with the {% component %}
template tag, this will be the name under which the component was registered in the ComponentRegistry
.
Otherwise, this will be None
.
Example:
@register("my_component")
class MyComponent(Component):
template = "{{ name }}"
def get_template_data(self, args, kwargs, slots, context):
return {
"name": self.registered_name,
}
Will print my_component
in the template:
{% component "my_component" / %}
And None
when rendered in Python:
MyComponent.render()
# None
request instance-attribute
¤
HTTPRequest object passed to this component.
Example:
class MyComponent(Component):
def get_template_data(self, args, kwargs, slots, context):
user_id = self.request.GET['user_id']
return {
'user_id': user_id,
}
Passing request
to a component:
In regular Django templates, you have to use RequestContext
to pass the HttpRequest
object to the template.
With Components, you can either use RequestContext
, or pass the request
object explicitly via Component.render()
and Component.render_to_response()
.
When a component is nested in another, the child component uses parent's request
object.
response_class class-attribute
¤
This attribute configures what class is used to generate response from Component.render_to_response()
.
The response class should accept a string as the first argument.
Defaults to django.http.HttpResponse
.
Example:
from django.http import HttpResponse
from django_components import Component
class MyHttpResponse(HttpResponse):
...
class MyComponent(Component):
response_class = MyHttpResponse
response = MyComponent.render_to_response()
assert isinstance(response, MyHttpResponse)
slots instance-attribute
¤
Slots passed to the component.
This is part of the Render API.
slots
has the same behavior as the slots
argument of Component.get_template_data()
:
Component.Slots
class, then the slots
property will return an instance of that class.slots
will be a plain dict.Example:
With Slots
class:
from django_components import Component, Slot, SlotInput
class Table(Component):
class Slots(NamedTuple):
header: SlotInput
footer: SlotInput
def on_render_before(self, context: Context, template: Optional[Template]) -> None:
assert isinstance(self.slots.header, Slot)
assert isinstance(self.slots.footer, Slot)
rendered = Table.render(
slots={
"header": "MY_HEADER",
"footer": lambda ctx: "FOOTER: " + ctx.data["user_id"],
},
)
Without Slots
class:
from django_components import Component, Slot, SlotInput
class Table(Component):
def on_render_before(self, context: Context, template: Optional[Template]) -> None:
assert isinstance(self.slots["header"], Slot)
assert isinstance(self.slots["footer"], Slot)
template class-attribute
instance-attribute
¤
Inlined Django template (as a plain string) associated with this component.
Example:
class Table(Component):
template = '''
<div>
{{ my_var }}
</div>
'''
Syntax highlighting
When using the inlined template, you can enable syntax highlighting with django_components.types.django_html
.
Learn more about syntax highlighting.
from django_components import Component, types
class MyComponent(Component):
template: types.django_html = '''
<div>
{{ my_var }}
</div>
'''
template_file class-attribute
¤
Filepath to the Django template associated with this component.
The filepath must be either:
COMPONENTS.dirs
or COMPONENTS.app_dirs
(e.g. <root>/components/
).TEMPLATES
setting (e.g. <root>/templates/
).Example:
Assuming this project layout:
|- components/
|- table/
|- table.html
|- table.css
|- table.js
Template name can be either relative to the python file (components/table/table.py
):
class Table(Component):
template_file = "table.html"
Or relative to one of the directories in COMPONENTS.dirs
or COMPONENTS.app_dirs
(components/
):
class Table(Component):
template_file = "table/table.html"
get_context_data ¤
DEPRECATED: Use get_template_data()
instead. Will be removed in v2.
Use this method to define variables that will be available in the template.
Receives the args and kwargs as they were passed to the Component.
This method has access to the Render API.
Read more about Template variables.
Example:
class MyComponent(Component):
def get_context_data(self, name, *args, **kwargs):
return {
"name": name,
"id": self.id,
}
template = "Hello, {{ name }}!"
MyComponent.render(name="World")
Warning
get_context_data()
and get_template_data()
are mutually exclusive.
If both methods return non-empty dictionaries, an error will be raised.
get_css_data ¤
Use this method to define variables that will be available from within the component's CSS code.
This method has access to the Render API.
The data returned from this method will be serialized to string.
Read more about CSS variables.
Example:
class MyComponent(Component):
def get_css_data(self, args, kwargs, slots, context):
return {
"color": kwargs["color"],
}
css = '''
.my-class {
color: var(--color);
}
'''
MyComponent.render(color="red")
Args:
args
: Positional arguments passed to the component.kwargs
: Keyword arguments passed to the component.slots
: Slots passed to the component.context
: Context
used for rendering the component template.Pass-through kwargs:
It's best practice to explicitly define what args and kwargs a component accepts.
However, if you want a looser setup, you can easily write components that accept any number of kwargs, and pass them all to the CSS code.
To do that, simply return the kwargs
dictionary itself from get_css_data()
:
class MyComponent(Component):
def get_css_data(self, args, kwargs, slots, context):
return kwargs
Type hints:
To get type hints for the args
, kwargs
, and slots
parameters, you can define the Args
, Kwargs
, and Slots
classes on the component class, and then directly reference them in the function signature of get_css_data()
.
When you set these classes, the args
, kwargs
, and slots
parameters will be given as instances of these (args
instance of Args
, etc).
When you omit these classes, or set them to None
, then the args
, kwargs
, and slots
parameters will be given as plain lists / dictionaries, unmodified.
Read more on Typing and validation.
Example:
from typing import NamedTuple
from django.template import Context
from django_components import Component, SlotInput
class MyComponent(Component):
class Args(NamedTuple):
color: str
class Kwargs(NamedTuple):
size: int
class Slots(NamedTuple):
footer: SlotInput
def get_css_data(self, args: Args, kwargs: Kwargs, slots: Slots, context: Context):
assert isinstance(args, MyComponent.Args)
assert isinstance(kwargs, MyComponent.Kwargs)
assert isinstance(slots, MyComponent.Slots)
return {
"color": args.color,
"size": kwargs.size,
}
You can also add typing to the data returned from get_css_data()
by defining the CssData
class on the component class.
When you set this class, you can return either the data as a plain dictionary, or an instance of CssData
.
If you return plain dictionary, the data will be validated against the CssData
class by instantiating it with the dictionary.
Example:
class MyComponent(Component):
class CssData(NamedTuple):
color: str
size: int
def get_css_data(self, args, kwargs, slots, context):
return {
"color": kwargs["color"],
"size": kwargs["size"],
}
# or
return MyComponent.CssData(
color=kwargs["color"],
size=kwargs["size"],
)
get_js_data ¤
Use this method to define variables that will be available from within the component's JavaScript code.
This method has access to the Render API.
The data returned from this method will be serialized to JSON.
Read more about JavaScript variables.
Example:
class MyComponent(Component):
def get_js_data(self, args, kwargs, slots, context):
return {
"name": kwargs["name"],
"id": self.id,
}
js = '''
$onLoad(({ name, id }) => {
console.log(name, id);
});
'''
MyComponent.render(name="World")
Args:
args
: Positional arguments passed to the component.kwargs
: Keyword arguments passed to the component.slots
: Slots passed to the component.context
: Context
used for rendering the component template.Pass-through kwargs:
It's best practice to explicitly define what args and kwargs a component accepts.
However, if you want a looser setup, you can easily write components that accept any number of kwargs, and pass them all to the JavaScript code.
To do that, simply return the kwargs
dictionary itself from get_js_data()
:
class MyComponent(Component):
def get_js_data(self, args, kwargs, slots, context):
return kwargs
Type hints:
To get type hints for the args
, kwargs
, and slots
parameters, you can define the Args
, Kwargs
, and Slots
classes on the component class, and then directly reference them in the function signature of get_js_data()
.
When you set these classes, the args
, kwargs
, and slots
parameters will be given as instances of these (args
instance of Args
, etc).
When you omit these classes, or set them to None
, then the args
, kwargs
, and slots
parameters will be given as plain lists / dictionaries, unmodified.
Read more on Typing and validation.
Example:
from typing import NamedTuple
from django.template import Context
from django_components import Component, SlotInput
class MyComponent(Component):
class Args(NamedTuple):
color: str
class Kwargs(NamedTuple):
size: int
class Slots(NamedTuple):
footer: SlotInput
def get_js_data(self, args: Args, kwargs: Kwargs, slots: Slots, context: Context):
assert isinstance(args, MyComponent.Args)
assert isinstance(kwargs, MyComponent.Kwargs)
assert isinstance(slots, MyComponent.Slots)
return {
"color": args.color,
"size": kwargs.size,
"id": self.id,
}
You can also add typing to the data returned from get_js_data()
by defining the JsData
class on the component class.
When you set this class, you can return either the data as a plain dictionary, or an instance of JsData
.
If you return plain dictionary, the data will be validated against the JsData
class by instantiating it with the dictionary.
Example:
class MyComponent(Component):
class JsData(NamedTuple):
color: str
size: int
def get_js_data(self, args, kwargs, slots, context):
return {
"color": kwargs["color"],
"size": kwargs["size"],
}
# or
return MyComponent.JsData(
color=kwargs["color"],
size=kwargs["size"],
)
get_template_data ¤
Use this method to define variables that will be available in the template.
This method has access to the Render API.
Read more about Template variables.
Example:
class MyComponent(Component):
def get_template_data(self, args, kwargs, slots, context):
return {
"name": kwargs["name"],
"id": self.id,
}
template = "Hello, {{ name }}!"
MyComponent.render(name="World")
Args:
args
: Positional arguments passed to the component.kwargs
: Keyword arguments passed to the component.slots
: Slots passed to the component.context
: Context
used for rendering the component template.Pass-through kwargs:
It's best practice to explicitly define what args and kwargs a component accepts.
However, if you want a looser setup, you can easily write components that accept any number of kwargs, and pass them all to the template (similar to django-cotton).
To do that, simply return the kwargs
dictionary itself from get_template_data()
:
class MyComponent(Component):
def get_template_data(self, args, kwargs, slots, context):
return kwargs
Type hints:
To get type hints for the args
, kwargs
, and slots
parameters, you can define the Args
, Kwargs
, and Slots
classes on the component class, and then directly reference them in the function signature of get_template_data()
.
When you set these classes, the args
, kwargs
, and slots
parameters will be given as instances of these (args
instance of Args
, etc).
When you omit these classes, or set them to None
, then the args
, kwargs
, and slots
parameters will be given as plain lists / dictionaries, unmodified.
Read more on Typing and validation.
Example:
from typing import NamedTuple
from django.template import Context
from django_components import Component, SlotInput
class MyComponent(Component):
class Args(NamedTuple):
color: str
class Kwargs(NamedTuple):
size: int
class Slots(NamedTuple):
footer: SlotInput
def get_template_data(self, args: Args, kwargs: Kwargs, slots: Slots, context: Context):
assert isinstance(args, MyComponent.Args)
assert isinstance(kwargs, MyComponent.Kwargs)
assert isinstance(slots, MyComponent.Slots)
return {
"color": args.color,
"size": kwargs.size,
"id": self.id,
}
You can also add typing to the data returned from get_template_data()
by defining the TemplateData
class on the component class.
When you set this class, you can return either the data as a plain dictionary, or an instance of TemplateData
.
If you return plain dictionary, the data will be validated against the TemplateData
class by instantiating it with the dictionary.
Example:
class MyComponent(Component):
class TemplateData(NamedTuple):
color: str
size: int
def get_template_data(self, args, kwargs, slots, context):
return {
"color": kwargs["color"],
"size": kwargs["size"],
}
# or
return MyComponent.TemplateData(
color=kwargs["color"],
size=kwargs["size"],
)
Warning
get_template_data()
and get_context_data()
are mutually exclusive.
If both methods return non-empty dictionaries, an error will be raised.
inject ¤
Use this method to retrieve the data that was passed to a {% provide %}
tag with the corresponding key.
To retrieve the data, inject()
must be called inside a component that's inside the {% provide %}
tag.
You may also pass a default that will be used if the {% provide %}
tag with given key was NOT found.
This method is part of the Render API, and raises an error if called from outside the rendering execution.
Read more about Provide / Inject.
Example:
Given this template:
{% provide "my_provide" message="hello" %}
{% component "my_comp" / %}
{% endprovide %}
And given this definition of "my_comp" component:
from django_components import Component, register
@register("my_comp")
class MyComp(Component):
template = "hi {{ message }}!"
def get_template_data(self, args, kwargs, slots, context):
data = self.inject("my_provide")
message = data.message
return {"message": message}
This renders into:
As the {{ message }}
is taken from the "my_provide" provider.
on_render ¤
This method does the actual rendering.
Read more about this hook in Component hooks.
You can override this method to:
The default implementation renders the component's Template with the given Context.
class MyTable(Component):
def on_render(self, context, template):
if template is None:
return None
else:
return template.render(context)
The template
argument is None
if the component has no template.
Modifying rendered template
To change what gets rendered, you can:
class MyTable(Component):
def on_render(self, context, template):
return "Hello"
Post-processing rendered template
To access the final output, you can yield
the result instead of returning it.
This will return a tuple of (rendered HTML, error). The error is None
if the rendering succeeded.
class MyTable(Component):
def on_render(self, context, template):
html, error = yield template.render(context)
if error is None:
# The rendering succeeded
return html
else:
# The rendering failed
print(f"Error: {error}")
At this point you can do 3 things:
Return a new HTML
The new HTML will be used as the final output.
If the original template raised an error, it will be ignored.
class MyTable(Component):
def on_render(self, context, template):
html, error = yield template.render(context)
return "NEW HTML"
Raise a new exception
The new exception is what will bubble up from the component.
The original HTML and original error will be ignored.
class MyTable(Component):
def on_render(self, context, template):
html, error = yield template.render(context)
raise Exception("Error message")
Return nothing (or None
) to handle the result as usual
If you don't raise an exception, and neither return a new HTML, then original HTML / error will be used:
class MyTable(Component):
def on_render(self, context, template):
html, error = yield template.render(context)
if error is not None:
# The rendering failed
print(f"Error: {error}")
on_render_after ¤
Hook that runs when the component was fully rendered, including all its children.
It receives the same arguments as on_render_before()
, plus the outcome of the rendering:
result
: The rendered output of the component. None
if the rendering failed.error
: The error that occurred during the rendering, or None
if the rendering succeeded.on_render_after()
behaves the same way as the second part of on_render()
(after the yield
).
class MyTable(Component):
def on_render_after(self, context, template, result, error):
if error is None:
# The rendering succeeded
return result
else:
# The rendering failed
print(f"Error: {error}")
Same as on_render()
, you can return a new HTML, raise a new exception, or return nothing:
Return a new HTML
The new HTML will be used as the final output.
If the original template raised an error, it will be ignored.
class MyTable(Component):
def on_render_after(self, context, template, result, error):
return "NEW HTML"
Raise a new exception
The new exception is what will bubble up from the component.
The original HTML and original error will be ignored.
class MyTable(Component):
def on_render_after(self, context, template, result, error):
raise Exception("Error message")
Return nothing (or None
) to handle the result as usual
If you don't raise an exception, and neither return a new HTML, then original HTML / error will be used:
class MyTable(Component):
def on_render_after(self, context, template, result, error):
if error is not None:
# The rendering failed
print(f"Error: {error}")
on_render_before ¤
on_render_before(context: Context, template: Optional[Template]) -> None
Runs just before the component's template is rendered.
It is called for every component, including nested ones, as part of the component render lifecycle.
Parameters:
context
(Context
) –
The Django Context that will be used to render the component's template.
template
(Optional[Template]
) –
The Django Template instance that will be rendered, or None
if no template.
Returns:
None
–
None. This hook is for side effects only.
Example:
You can use this hook to access the context or the template:
from django.template import Context, Template
from django_components import Component
class MyTable(Component):
def on_render_before(self, context: Context, template: Optional[Template]) -> None:
# Insert value into the Context
context["from_on_before"] = ":)"
assert isinstance(template, Template)
Warning
If you want to pass data to the template, prefer using get_template_data()
instead of this hook.
Warning
Do NOT modify the template in this hook. The template is reused across renders.
Since this hook is called for every component, this means that the template would be modified every time a component is rendered.
render classmethod
¤
render(
context: Optional[Union[Dict[str, Any], Context]] = None,
args: Optional[Any] = None,
kwargs: Optional[Any] = None,
slots: Optional[Any] = None,
deps_strategy: DependenciesStrategy = "document",
type: Optional[DependenciesStrategy] = None,
render_dependencies: bool = True,
request: Optional[HttpRequest] = None,
outer_context: Optional[Context] = None,
registry: Optional[ComponentRegistry] = None,
registered_name: Optional[str] = None,
node: Optional[ComponentNode] = None,
) -> str
Render the component into a string. This is the equivalent of calling the {% component %}
tag.
Button.render(
args=["John"],
kwargs={
"surname": "Doe",
"age": 30,
},
slots={
"footer": "i AM A SLOT",
},
)
Inputs:
args
- Optional. A list of positional args for the component. This is the same as calling the component as:
{% component "button" arg1 arg2 ... %}
kwargs
- Optional. A dictionary of keyword arguments for the component. This is the same as calling the component as:
{% component "button" key1=val1 key2=val2 ... %}
slots
- Optional. A dictionary of slot fills. This is the same as passing {% fill %}
tags to the component.
{% component "button" %}
{% fill "content" %}
Click me!
{% endfill %}
{% endcomponent %}
Dictionary keys are the slot names. Dictionary values are the slot fills.
Slot fills can be strings, render functions, or Slot
instances:
Button.render(
slots={
"content": "Click me!"
"content2": lambda ctx: "Click me!",
"content3": Slot(lambda ctx: "Click me!"),
},
)
context
- Optional. Plain dictionary or Django's Context. The context within which the component is rendered.
When a component is rendered within a template with the {% component %}
tag, this will be set to the Context instance that is used for rendering the template.
When you call Component.render()
directly from Python, you can ignore this input most of the time. Instead use args
, kwargs
, and slots
to pass data to the component.
You can pass RequestContext
to the context
argument, so that the component will gain access to the request object and will use context processors. Read more on Working with HTTP requests.
Button.render(
context=RequestContext(request),
)
For advanced use cases, you can use context
argument to "pre-render" the component in Python, and then pass the rendered output as plain string to the template. With this, the inner component is rendered as if it was within the template with {% component %}
.
class Button(Component):
def render(self, context, template):
# Pass `context` to Icon component so it is rendered
# as if nested within Button.
icon = Icon.render(
context=context,
args=["icon-name"],
deps_strategy="ignore",
)
# Update context with icon
with context.update({"icon": icon}):
return template.render(context)
Whether the variables defined in context
are available to the template depends on the context behavior mode:
In "django"
context behavior mode, the template will have access to the keys of this context.
In "isolated"
context behavior mode, the template will NOT have access to this context, and data MUST be passed via component's args and kwargs.
deps_strategy
- Optional. Configure how to handle JS and CSS dependencies. Read more about Dependencies rendering.
There are six strategies:
"document"
(default)
<head>
and <body>
tags."fragment"
"simple"
<head>
and <body>
tags."prepend"
"append"
"ignore"
render_dependencies()
.request
- Optional. HTTPRequest object. Pass a request object directly to the component to apply context processors.
Read more about Working with HTTP requests.
Type hints:
Component.render()
is NOT typed. To add type hints, you can wrap the inputs in component's Args
, Kwargs
, and Slots
classes.
Read more on Typing and validation.
from typing import NamedTuple, Optional
from django_components import Component, Slot, SlotInput
# Define the component with the types
class Button(Component):
class Args(NamedTuple):
name: str
class Kwargs(NamedTuple):
surname: str
age: int
class Slots(NamedTuple):
my_slot: Optional[SlotInput] = None
footer: SlotInput
# Add type hints to the render call
Button.render(
args=Button.Args(
name="John",
),
kwargs=Button.Kwargs(
surname="Doe",
age=30,
),
slots=Button.Slots(
footer=Slot(lambda ctx: "Click me!"),
),
)
render_to_response classmethod
¤
render_to_response(
context: Optional[Union[Dict[str, Any], Context]] = None,
args: Optional[Any] = None,
kwargs: Optional[Any] = None,
slots: Optional[Any] = None,
deps_strategy: DependenciesStrategy = "document",
type: Optional[DependenciesStrategy] = None,
render_dependencies: bool = True,
request: Optional[HttpRequest] = None,
outer_context: Optional[Context] = None,
registry: Optional[ComponentRegistry] = None,
registered_name: Optional[str] = None,
node: Optional[ComponentNode] = None,
**response_kwargs: Any
) -> HttpResponse
Render the component and wrap the content in an HTTP response class.
render_to_response()
takes the same inputs as Component.render()
. See that method for more information.
After the component is rendered, the HTTP response class is instantiated with the rendered content.
Any additional kwargs are passed to the response class.
Example:
Button.render_to_response(
args=["John"],
kwargs={
"surname": "Doe",
"age": 30,
},
slots={
"footer": "i AM A SLOT",
},
# HttpResponse kwargs
status=201,
headers={...},
)
# HttpResponse(content=..., status=201, headers=...)
Custom response class:
You can set a custom response class on the component via Component.response_class
. Defaults to django.http.HttpResponse
.
from django.http import HttpResponse
from django_components import Component
class MyHttpResponse(HttpResponse):
...
class MyComponent(Component):
response_class = MyHttpResponse
response = MyComponent.render_to_response()
assert isinstance(response, MyHttpResponse)
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4