Skip to content

components ¤

dynamic ¤

DynamicComponent ¤

DynamicComponent(
    registered_name: Optional[str] = None,
    component_id: Optional[str] = None,
    outer_context: Optional[Context] = None,
    fill_content: Optional[Dict[str, FillContent]] = None,
    registry: Optional[ComponentRegistry] = None,
)

Bases: Component

Dynamic component - This component takes inputs and renders the outputs depending on the is and registry arguments.

  • is - required - The component class or registered name of the component that will be rendered in this place.

  • registry - optional - Specify the registry to search for the registered name. If omitted, all registries are searched.

Source code in src/django_components/component.py
def __init__(
    self,
    registered_name: Optional[str] = None,
    component_id: Optional[str] = None,
    outer_context: Optional[Context] = None,
    fill_content: Optional[Dict[str, FillContent]] = None,
    registry: Optional[ComponentRegistry] = None,  # noqa F811
):
    # When user first instantiates the component class before calling
    # `render` or `render_to_response`, then we want to allow the render
    # function to make use of the instantiated object.
    #
    # So while `MyComp.render()` creates a new instance of MyComp internally,
    # if we do `MyComp(registered_name="abc").render()`, then we use the
    # already-instantiated object.
    #
    # To achieve that, we want to re-assign the class methods as instance methods.
    # For that we have to "unwrap" the class methods via __func__.
    # See https://stackoverflow.com/a/76706399/9788634
    self.render_to_response = types.MethodType(self.__class__.render_to_response.__func__, self)  # type: ignore
    self.render = types.MethodType(self.__class__.render.__func__, self)  # type: ignore
    self.as_view = types.MethodType(self.__class__.as_view.__func__, self)  # type: ignore

    self.registered_name: Optional[str] = registered_name
    self.outer_context: Context = outer_context or Context()
    self.fill_content = fill_content or {}
    self.component_id = component_id or gen_id()
    self.registry = registry or registry_
    self._render_stack: Deque[RenderStackItem[ArgsType, KwargsType, SlotsType]] = deque()
    # None == uninitialized, False == No types, Tuple == types
    self._types: Optional[Union[Tuple[Any, Any, Any, Any], Literal[False]]] = None

Media class-attribute instance-attribute ¤

Defines JS and CSS media files associated with this component.

css class-attribute instance-attribute ¤

css: Optional[str] = None

Inlined CSS associated with this component.

input property ¤

input: RenderInput[ArgsType, KwargsType, SlotsType]

Input holds the data (like arg, kwargs, slots) that were passsed to the current execution of the render method.

is_filled property ¤

is_filled: Dict[str, bool]

Dictionary describing which slots have or have not been filled.

This attribute is available for use only within the template as {{ component_vars.is_filled.slot_name }}, and within on_render_before and on_render_after hooks.

js class-attribute instance-attribute ¤

js: Optional[str] = None

Inlined JS associated with this component.

media instance-attribute ¤

media: Media

Normalized definition of JS and CSS media files associated with this component.

NOTE: This field is generated from Component.Media class.

response_class class-attribute instance-attribute ¤

response_class = HttpResponse

This allows to configure what class is used to generate response from render_to_response

template_name class-attribute instance-attribute ¤

template_name: Optional[str] = None

Filepath to the Django template associated with this component.

The filepath must be relative to either the file where the component class was defined, or one of the roots of STATIFILES_DIRS.

Only one of template_name, get_template_name, template or get_template must be defined.

as_view classmethod ¤

as_view(**initkwargs: Any) -> ViewFn

Shortcut for calling Component.View.as_view and passing component instance to it.

Source code in src/django_components/component.py
@classmethod
def as_view(cls, **initkwargs: Any) -> ViewFn:
    """
    Shortcut for calling `Component.View.as_view` and passing component instance to it.
    """
    # This method may be called as class method or as instance method.
    # If called as class method, create a new instance.
    if isinstance(cls, Component):
        comp: Component = cls
    else:
        comp = cls()

    # Allow the View class to access this component via `self.component`
    return comp.View.as_view(**initkwargs, component=comp)

get_template ¤

get_template(context: Context) -> Optional[Union[str, Template]]

Inlined Django template associated with this component. Can be a plain string or a Template instance.

Only one of template_name, get_template_name, template or get_template must be defined.

Source code in src/django_components/component.py
def get_template(self, context: Context) -> Optional[Union[str, Template]]:
    """
    Inlined Django template associated with this component. Can be a plain string or a Template instance.

    Only one of `template_name`, `get_template_name`, `template` or `get_template` must be defined.
    """
    return None

get_template_name ¤

get_template_name(context: Context) -> Optional[str]

Filepath to the Django template associated with this component.

The filepath must be relative to either the file where the component class was defined, or one of the roots of STATIFILES_DIRS.

Only one of template_name, get_template_name, template or get_template must be defined.

Source code in src/django_components/component.py
def get_template_name(self, context: Context) -> Optional[str]:
    """
    Filepath to the Django template associated with this component.

    The filepath must be relative to either the file where the component class was defined,
    or one of the roots of `STATIFILES_DIRS`.

    Only one of `template_name`, `get_template_name`, `template` or `get_template` must be defined.
    """
    return None

inject ¤

inject(key: str, default: Optional[Any] = None) -> Any

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 mut be used inside the get_context_data() method and raises an error if called elsewhere.

Example:

Given this template:

{% provide "provider" hello="world" %}
    {% component "my_comp" %}
    {% endcomponent %}
{% endprovide %}

And given this definition of "my_comp" component:

from django_components import Component, register

@register("my_comp")
class MyComp(Component):
    template = "hi {{ data.hello }}!"
    def get_context_data(self):
        data = self.inject("provider")
        return {"data": data}

This renders into:

hi world!

As the {{ data.hello }} is taken from the "provider".

Source code in src/django_components/component.py
def inject(self, key: str, default: Optional[Any] = None) -> Any:
    """
    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 mut be used inside the `get_context_data()` method and raises
    an error if called elsewhere.

    Example:

    Given this template:
    ```django
    {% provide "provider" hello="world" %}
        {% component "my_comp" %}
        {% endcomponent %}
    {% endprovide %}
    ```

    And given this definition of "my_comp" component:
    ```py
    from django_components import Component, register

    @register("my_comp")
    class MyComp(Component):
        template = "hi {{ data.hello }}!"
        def get_context_data(self):
            data = self.inject("provider")
            return {"data": data}
    ```

    This renders into:
    ```
    hi world!
    ```

    As the `{{ data.hello }}` is taken from the "provider".
    """
    if self.input is None:
        raise RuntimeError(
            f"Method 'inject()' of component '{self.name}' was called outside of 'get_context_data()'"
        )

    return get_injected_context_var(self.name, self.input.context, key, default)

on_render_after ¤

on_render_after(context: Context, template: Template, content: str) -> Optional[SlotResult]

Hook that runs just after the component's template was rendered. It receives the rendered output as the last argument.

You can use this hook to access the context or the template, but modifying them won't have any effect.

To override the content that gets rendered, you can return a string or SafeString from this hook.

Source code in src/django_components/component.py
def on_render_after(self, context: Context, template: Template, content: str) -> Optional[SlotResult]:
    """
    Hook that runs just after the component's template was rendered.
    It receives the rendered output as the last argument.

    You can use this hook to access the context or the template, but modifying
    them won't have any effect.

    To override the content that gets rendered, you can return a string or SafeString
    from this hook.
    """
    pass

on_render_before ¤

on_render_before(context: Context, template: Template) -> None

Hook that runs just before the component's template is rendered.

You can use this hook to access or modify the context or the template.

Source code in src/django_components/component.py
def on_render_before(self, context: Context, template: Template) -> None:
    """
    Hook that runs just before the component's template is rendered.

    You can use this hook to access or modify the context or the template.
    """
    pass

render classmethod ¤

render(
    context: Optional[Union[Dict[str, Any], Context]] = None,
    args: Optional[ArgsType] = None,
    kwargs: Optional[KwargsType] = None,
    slots: Optional[SlotsType] = None,
    escape_slots_content: bool = True,
) -> str

Render the component into a string.

Inputs: - args - Positional args for the component. This is the same as calling the component as {% component "my_comp" arg1 arg2 ... %} - kwargs - Kwargs for the component. This is the same as calling the component as {% component "my_comp" key1=val1 key2=val2 ... %} - slots - Component slot fills. This is the same as pasing {% fill %} tags to the component. Accepts a dictionary of { slot_name: slot_content } where slot_content can be a string or render function. - escape_slots_content - Whether the content from slots should be escaped. - context - A context (dictionary or Django's Context) within which the component is rendered. The keys on the context can be accessed from within the template. - NOTE: In "isolated" mode, context is NOT accessible, and data MUST be passed via component's args and kwargs.

Example:

MyComponent.render(
    args=[1, "two", {}],
    kwargs={
        "key": 123,
    },
    slots={
        "header": 'STATIC TEXT HERE',
        "footer": lambda ctx, slot_kwargs, slot_ref: f'CTX: {ctx['hello']} SLOT_DATA: {slot_kwargs['abc']}',
    },
    escape_slots_content=False,
)

Source code in src/django_components/component.py
@classmethod
def render(
    cls,
    context: Optional[Union[Dict[str, Any], Context]] = None,
    args: Optional[ArgsType] = None,
    kwargs: Optional[KwargsType] = None,
    slots: Optional[SlotsType] = None,
    escape_slots_content: bool = True,
) -> str:
    """
    Render the component into a string.

    Inputs:
    - `args` - Positional args for the component. This is the same as calling the component
      as `{% component "my_comp" arg1 arg2 ... %}`
    - `kwargs` - Kwargs for the component. This is the same as calling the component
      as `{% component "my_comp" key1=val1 key2=val2 ... %}`
    - `slots` - Component slot fills. This is the same as pasing `{% fill %}` tags to the component.
        Accepts a dictionary of `{ slot_name: slot_content }` where `slot_content` can be a string
        or render function.
    - `escape_slots_content` - Whether the content from `slots` should be escaped.
    - `context` - A context (dictionary or Django's Context) within which the component
      is rendered. The keys on the context can be accessed from within the template.
        - NOTE: In "isolated" mode, context is NOT accessible, and data MUST be passed via
          component's args and kwargs.

    Example:
    ```py
    MyComponent.render(
        args=[1, "two", {}],
        kwargs={
            "key": 123,
        },
        slots={
            "header": 'STATIC TEXT HERE',
            "footer": lambda ctx, slot_kwargs, slot_ref: f'CTX: {ctx['hello']} SLOT_DATA: {slot_kwargs['abc']}',
        },
        escape_slots_content=False,
    )
    ```
    """
    # This method may be called as class method or as instance method.
    # If called as class method, create a new instance.
    if isinstance(cls, Component):
        comp: Component = cls
    else:
        comp = cls()

    return comp._render(context, args, kwargs, slots, escape_slots_content)

render_css_dependencies ¤

render_css_dependencies() -> SafeString

Render only CSS dependencies available in the media class or provided as a string.

Source code in src/django_components/component.py
def render_css_dependencies(self) -> SafeString:
    """Render only CSS dependencies available in the media class or provided as a string."""
    if self.css is not None:
        return mark_safe(f"<style>{self.css}</style>")
    return mark_safe("\n".join(self.media.render_css()))

render_dependencies ¤

render_dependencies() -> SafeString

Helper function to render all dependencies for a component.

Source code in src/django_components/component.py
def render_dependencies(self) -> SafeString:
    """Helper function to render all dependencies for a component."""
    dependencies = []

    css_deps = self.render_css_dependencies()
    if css_deps:
        dependencies.append(css_deps)

    js_deps = self.render_js_dependencies()
    if js_deps:
        dependencies.append(js_deps)

    return mark_safe("\n".join(dependencies))

render_js_dependencies ¤

render_js_dependencies() -> SafeString

Render only JS dependencies available in the media class or provided as a string.

Source code in src/django_components/component.py
def render_js_dependencies(self) -> SafeString:
    """Render only JS dependencies available in the media class or provided as a string."""
    if self.js is not None:
        return mark_safe(f"<script>{self.js}</script>")
    return mark_safe("\n".join(self.media.render_js()))

render_to_response classmethod ¤

render_to_response(
    context: Optional[Union[Dict[str, Any], Context]] = None,
    slots: Optional[SlotsType] = None,
    escape_slots_content: bool = True,
    args: Optional[ArgsType] = None,
    kwargs: Optional[KwargsType] = None,
    *response_args: Any,
    **response_kwargs: Any
) -> HttpResponse

Render the component and wrap the content in the response class.

The response class is taken from Component.response_class. Defaults to django.http.HttpResponse.

This is the interface for the django.views.View class which allows us to use components as Django views with component.as_view().

Inputs: - args - Positional args for the component. This is the same as calling the component as {% component "my_comp" arg1 arg2 ... %} - kwargs - Kwargs for the component. This is the same as calling the component as {% component "my_comp" key1=val1 key2=val2 ... %} - slots - Component slot fills. This is the same as pasing {% fill %} tags to the component. Accepts a dictionary of { slot_name: slot_content } where slot_content can be a string or render function. - escape_slots_content - Whether the content from slots should be escaped. - context - A context (dictionary or Django's Context) within which the component is rendered. The keys on the context can be accessed from within the template. - NOTE: In "isolated" mode, context is NOT accessible, and data MUST be passed via component's args and kwargs.

Any additional args and kwargs are passed to the response_class.

Example:

MyComponent.render_to_response(
    args=[1, "two", {}],
    kwargs={
        "key": 123,
    },
    slots={
        "header": 'STATIC TEXT HERE',
        "footer": lambda ctx, slot_kwargs, slot_ref: f'CTX: {ctx['hello']} SLOT_DATA: {slot_kwargs['abc']}',
    },
    escape_slots_content=False,
    # HttpResponse input
    status=201,
    headers={...},
)
# HttpResponse(content=..., status=201, headers=...)

Source code in src/django_components/component.py
@classmethod
def render_to_response(
    cls,
    context: Optional[Union[Dict[str, Any], Context]] = None,
    slots: Optional[SlotsType] = None,
    escape_slots_content: bool = True,
    args: Optional[ArgsType] = None,
    kwargs: Optional[KwargsType] = None,
    *response_args: Any,
    **response_kwargs: Any,
) -> HttpResponse:
    """
    Render the component and wrap the content in the response class.

    The response class is taken from `Component.response_class`. Defaults to `django.http.HttpResponse`.

    This is the interface for the `django.views.View` class which allows us to
    use components as Django views with `component.as_view()`.

    Inputs:
    - `args` - Positional args for the component. This is the same as calling the component
      as `{% component "my_comp" arg1 arg2 ... %}`
    - `kwargs` - Kwargs for the component. This is the same as calling the component
      as `{% component "my_comp" key1=val1 key2=val2 ... %}`
    - `slots` - Component slot fills. This is the same as pasing `{% fill %}` tags to the component.
        Accepts a dictionary of `{ slot_name: slot_content }` where `slot_content` can be a string
        or render function.
    - `escape_slots_content` - Whether the content from `slots` should be escaped.
    - `context` - A context (dictionary or Django's Context) within which the component
      is rendered. The keys on the context can be accessed from within the template.
        - NOTE: In "isolated" mode, context is NOT accessible, and data MUST be passed via
          component's args and kwargs.

    Any additional args and kwargs are passed to the `response_class`.

    Example:
    ```py
    MyComponent.render_to_response(
        args=[1, "two", {}],
        kwargs={
            "key": 123,
        },
        slots={
            "header": 'STATIC TEXT HERE',
            "footer": lambda ctx, slot_kwargs, slot_ref: f'CTX: {ctx['hello']} SLOT_DATA: {slot_kwargs['abc']}',
        },
        escape_slots_content=False,
        # HttpResponse input
        status=201,
        headers={...},
    )
    # HttpResponse(content=..., status=201, headers=...)
    ```
    """
    content = cls.render(
        args=args,
        kwargs=kwargs,
        context=context,
        slots=slots,
        escape_slots_content=escape_slots_content,
    )
    return cls.response_class(content, *response_args, **response_kwargs)