Skip to content

Component context and scope

By default, context variables are passed down the template as in regular Django - deeper scopes can access the variables from the outer scopes. So if you have several nested forloops, then inside the deep-most loop you can access variables defined by all previous loops.

With this in mind, the {% component %} tag behaves similarly to {% include %} tag - inside the component tag, you can access all variables that were defined outside of it.

And just like with {% include %}, if you don't want a specific component template to have access to the parent context, add only to the {% component %} tag:

{% component "calendar" date="2015-06-19" only / %}

NOTE: {% csrf_token %} tags need access to the top-level context, and they will not function properly if they are rendered in a component that is called with the only modifier.

If you find yourself using the only modifier often, you can set the context_behavior option to "isolated", which automatically applies the only modifier. This is useful if you want to make sure that components don't accidentally access the outer context.

Components can also access the outer context in their context methods like get_context_data by accessing the property self.outer_context.

Example of Accessing Outer Context¤

<div>
  {% component "calender" / %}
</div>

Assuming that the rendering context has variables such as date, you can use self.outer_context to access them from within get_context_data. Here's how you might implement it:

class Calender(Component):

    ...

    def get_context_data(self):
        outer_field = self.outer_context["date"]
        return {
            "date": outer_fields,
        }

However, as a best practice, it’s recommended not to rely on accessing the outer context directly through self.outer_context. Instead, explicitly pass the variables to the component. For instance, continue passing the variables in the component tag as shown in the previous examples.

Context behavior¤

django_components supports both Django and Vue-like behavior when it comes to passing data to and through components. This can be configured in context_behavior.

This has two modes:

  • "django"

    The default Django template behavior.

    Inside the {% fill %} tag, the context variables you can access are a union of:

  • "isolated"

    Similar behavior to Vue or React, this is useful if you want to make sure that components don't accidentally access variables defined outside of the component.

    Inside the {% fill %} tag, you can ONLY access variables from 2 places:

Warning

Notice that the component whose get_context_data() we use inside {% fill %} is NOT the same across the two modes!

Consider this example:

class Outer(Component):
    template = \"\"\"
      <div>
        {% component "inner" %}
          {% fill "content" %}
            {{ my_var }}
          {% endfill %}
        {% endcomponent %}
      </div>
    \"\"\"
  • "django" - my_var has access to data from get_context_data() of both Inner and Outer. If there are variables defined in both, then Inner overshadows Outer.

  • "isolated" - my_var has access to data from get_context_data() of ONLY Outer.

Example "django"¤

Given this template:

@register("root_comp")
class RootComp(Component):
    template = """
        {% with cheese="feta" %}
            {% component 'my_comp' %}
                {{ my_var }}  # my_var
                {{ cheese }}  # cheese
            {% endcomponent %}
        {% endwith %}
    """

    def get_context_data(self):
        return { "my_var": 123 }

Then if get_context_data() of the component "my_comp" returns following data:

{ "my_var": 456 }

Then the template will be rendered as:

456   # my_var
feta  # cheese

Because "my_comp" overshadows the outer variable "my_var", so {{ my_var }} equals 456.

And variable "cheese" equals feta, because the fill CAN access all the data defined in the outer layers, like the {% with %} tag.

Example "isolated"¤

Given this template:

class RootComp(Component):
    template = """
        {% with cheese="feta" %}
            {% component 'my_comp' %}
                {{ my_var }}  # my_var
                {{ cheese }}  # cheese
            {% endcomponent %}
        {% endwith %}
    """

    def get_context_data(self):
        return { "my_var": 123 }

Then if get_context_data() of the component "my_comp" returns following data:

{ "my_var": 456 }

Then the template will be rendered as:

123   # my_var
    # cheese

Because variables "my_var" and "cheese" are searched only inside RootComponent.get_context_data(). But since "cheese" is not defined there, it's empty.

Info

Notice that the variables defined with the {% with %} tag are ignored inside the {% fill %} tag with the "isolated" mode.