refactor: Update docs and tests to use get_template_data() (#1161)

* refactor: update docs and tests to use get_template_data()

* refactor: fix linting

* docs: add note about difference between the two methods
This commit is contained in:
Juro Oravec 2025-05-03 12:04:10 +02:00 committed by GitHub
parent c69980493d
commit 28b61c1609
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
69 changed files with 795 additions and 725 deletions

View file

@ -98,8 +98,8 @@ class MyComponent(Component):
ttl = 300 # Cache for 5 minutes
cache_name = "my_cache"
def get_context_data(self, name, **kwargs):
return {"name": name}
def get_template_data(self, args, kwargs, slots, context):
return {"name": kwargs["name"]}
```
In this example, the component's rendered output is cached for 5 minutes using the `my_cache` backend.

View file

@ -12,7 +12,7 @@ NOTE: `{% csrf_token %}` tags need access to the top-level context, and they wil
If you find yourself using the `only` modifier often, you can set the [context_behavior](#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`.
Components can also access the outer context in their context methods like `get_template_data` by accessing the property `self.outer_context`.
## Example of Accessing Outer Context
@ -22,14 +22,14 @@ Components can also access the outer context in their context methods like `get_
</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:
Assuming that the rendering context has variables such as `date`, you can use `self.outer_context` to access them from within `get_template_data`. Here's how you might implement it:
```python
class Calender(Component):
...
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
outer_field = self.outer_context["date"]
return {
"date": outer_fields,
@ -56,7 +56,7 @@ This has two modes:
[`{% with %}`](https://docs.djangoproject.com/en/5.1/ref/templates/builtins/#with) tags.
- Any loops ([`{% for ... %}`](https://docs.djangoproject.com/en/5.1/ref/templates/builtins/#cycle))
that the `{% fill %}` tag is part of.
- Data returned from [`Component.get_context_data()`](../../../reference/api#django_components.Component.get_context_data)
- Data returned from [`Component.get_template_data()`](../../../reference/api#django_components.Component.get_template_data)
of the component that owns the fill tag.
- `"isolated"`
@ -69,12 +69,12 @@ This has two modes:
- Any loops ([`{% for ... %}`](https://docs.djangoproject.com/en/5.1/ref/templates/builtins/#cycle))
that the `{% fill %}` tag is part of.
- [`Component.get_context_data()`](../../../reference/api#django_components.Component.get_context_data)
- [`Component.get_template_data()`](../../../reference/api#django_components.Component.get_template_data)
of the component which defined the template (AKA the "root" component).
!!! warning
Notice that the component whose `get_context_data()` we use inside
Notice that the component whose `get_template_data()` we use inside
[`{% fill %}`](../../../reference/template_tags#fill)
is NOT the same across the two modes!
@ -93,10 +93,10 @@ This has two modes:
"""
```
- `"django"` - `my_var` has access to data from `get_context_data()` of both `Inner` and `Outer`.
- `"django"` - `my_var` has access to data from `get_template_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`.
- `"isolated"` - `my_var` has access to data from `get_template_data()` of ONLY `Outer`.
### Example "django"
@ -115,11 +115,11 @@ class RootComp(Component):
{% endwith %}
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return { "my_var": 123 }
```
Then if [`get_context_data()`](../../../reference/api#django_components.Component.get_context_data)
Then if [`get_template_data()`](../../../reference/api#django_components.Component.get_template_data)
of the component `"my_comp"` returns following data:
```py
@ -154,11 +154,11 @@ class RootComp(Component):
{% endwith %}
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return { "my_var": 123 }
```
Then if [`get_context_data()`](../../../reference/api#django_components.Component.get_context_data)
Then if [`get_template_data()`](../../../reference/api#django_components.Component.get_template_data)
of the component `"my_comp"` returns following data:
```py
@ -172,7 +172,7 @@ Then the template will be rendered as:
# cheese
```
Because variables `"my_var"` and `"cheese"` are searched only inside `RootComponent.get_context_data()`.
Because variables `"my_var"` and `"cheese"` are searched only inside `RootComponent.get_template_data()`.
But since `"cheese"` is not defined there, it's empty.
!!! info

View file

@ -12,9 +12,9 @@ class Calendar(Component):
template_file = "template.html"
# This component takes one parameter, a date string to show in the template
def get_context_data(self, date):
def get_template_data(self, args, kwargs, slots, context):
return {
"date": date,
"date": kwargs["date"],
}
```

View file

@ -42,7 +42,7 @@ Extensions can define methods to hook into lifecycle events, such as:
- Un/registering a component
- Creating or deleting a registry
- Pre-processing data passed to a component on render
- Post-processing data returned from [`get_context_data()`](../../../reference/api#django_components.Component.get_context_data)
- Post-processing data returned from [`get_template_data()`](../../../reference/api#django_components.Component.get_template_data)
and others.
See the full list in [Extension Hooks Reference](../../../reference/extension_hooks).
@ -122,7 +122,7 @@ For example, the View extension is available as `self.view`:
```python
class MyTable(Component):
def get_context_data(self, request):
def get_template_data(self, args, kwargs, slots, context):
# `self.view` points to the instance of `View` extension.
return {
"view": self.view,
@ -133,7 +133,7 @@ And the Storybook extension is available as `self.storybook`:
```python
class MyTable(Component):
def get_context_data(self, request):
def get_template_data(self, args, kwargs, slots, context):
# `self.storybook` points to the instance of `Storybook` extension.
return {
"title": self.storybook.title(),

View file

@ -78,7 +78,7 @@ In the example from previous section, we've defined two kwargs: `hello="hi" anot
```py
class ChildComponent(Component):
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
my_data = self.inject("my_data")
print(my_data.hello) # hi
print(my_data.another) # 123
@ -94,7 +94,7 @@ To avoid the error, you can pass a second argument to [`inject()`](../../../refe
```py
class ChildComponent(Component):
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
my_data = self.inject("invalid_key", DEFAULT_DATA)
assert my_data == DEFAULT_DATA
return {}
@ -119,7 +119,7 @@ class ChildComponent(Component):
<div> {{ my_data.another }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
my_data = self.inject("my_data", "default")
return {"my_data": my_data}

View file

@ -1,5 +1,5 @@
When a component is being rendered, the component inputs are passed to various methods like
[`get_context_data()`](../../../reference/api#django_components.Component.get_context_data),
[`get_template_data()`](../../../reference/api#django_components.Component.get_template_data),
[`get_js_data()`](../../../reference/api#django_components.Component.get_js_data),
or [`get_css_data()`](../../../reference/api#django_components.Component.get_css_data).
@ -24,10 +24,10 @@ class MyTable(Component):
position = "left"
selected_items = Default(lambda: [1, 2, 3])
def get_context_data(self, position, selected_items):
def get_template_data(self, args, kwargs, slots, context):
return {
"position": position,
"selected_items": selected_items,
"position": kwargs["position"],
"selected_items": kwargs["selected_items"],
}
...
@ -138,10 +138,10 @@ class MyTable(Component):
position = "left"
selected_items = Default(lambda: [1, 2, 3])
def get_context_data(self, position, selected_items):
def get_template_data(self, args, kwargs, slots, context):
return {
"position": position,
"selected_items": selected_items,
"position": kwargs["position"],
"selected_items": kwargs["selected_items"],
}
```

View file

@ -47,10 +47,10 @@ You can use this for example to allow users of your component to add extra attri
```djc_py
@register("my_comp")
class MyComp(Component):
# Capture extra kwargs in `attrs`
def get_context_data(self, **attrs):
# Pass all kwargs as `attrs`
def get_template_data(self, args, kwargs, slots, context):
return {
"attrs": attrs,
"attrs": kwargs,
"classes": "text-red",
"my_id": 123,
}
@ -607,10 +607,11 @@ class MyComp(Component):
</div>
"""
def get_context_data(self, date: Date, attrs: dict):
def get_template_data(self, args, kwargs, slots, context):
date = kwargs.pop("date")
return {
"date": date,
"attrs": attrs,
"attrs": kwargs,
"class_from_var": "extra-class"
}
@ -625,7 +626,7 @@ class Parent(Component):
/ %}
"""
def get_context_data(self, date: Date):
def get_template_data(self, args, kwargs, slots, context):
return {
"date": datetime.now(),
"json_data": json.dumps({"value": 456})
@ -669,7 +670,7 @@ So all kwargs that start with `attrs:` will be collected into an `attrs` dict.
attrs:@click="(e) => onClick(e, 'from_parent')"
```
And `get_context_data` of `MyComp` will receive `attrs` input with following keys:
And `get_template_data` of `MyComp` will receive a kwarg named `attrs` with following keys:
```py
attrs = {

View file

@ -100,6 +100,44 @@ class ProfileCard(Component):
}
```
There is a slight difference between [`get_context_data()`](../../../reference/api/#django_components.Component.get_context_data) and [`get_template_data()`](../../../reference/api/#django_components.Component.get_template_data)
when rendering a component with the [`{% component %}`](../../../reference/template_tags/#component) tag.
For example if you have component that accepts kwarg `date`:
```py
class MyComponent(Component):
def get_context_data(self, date, *args, **kwargs):
return {
"date": date,
}
def get_template_data(self, args, kwargs, slots, context):
return {
"date": kwargs["date"],
}
```
The difference is that:
- With [`get_context_data()`](../../../reference/api/#django_components.Component.get_context_data), you can pass `date` either as arg or kwarg:
```django
{% component "my_component" date=some_date %}
{% component "my_component" some_date %}
```
- But with [`get_template_data()`](../../../reference/api/#django_components.Component.get_template_data), `date` MUST be passed as kwarg:
```django
{% component "my_component" date=some_date %}
{% component "my_component" some_date %}
```
!!! warning
[`get_template_data()`](../../../reference/api/#django_components.Component.get_template_data)

View file

@ -48,7 +48,7 @@ When the component has access to the `request` object, the request object will b
```python
class MyComponent(Component):
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
'user_id': self.request.GET['user_id'],
}
@ -77,11 +77,11 @@ class MyComponent(Component):
MyComponent.render(request=request)
```
You can also access the context processors data from within [`get_context_data()`](../../../reference/api#django_components.Component.get_context_data) and other methods under [`Component.context_processors_data`](../../../reference/api#django_components.Component.context_processors_data).
You can also access the context processors data from within [`get_template_data()`](../../../reference/api#django_components.Component.get_template_data) and other methods under [`Component.context_processors_data`](../../../reference/api#django_components.Component.context_processors_data).
```python
class MyComponent(Component):
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
csrf_token = self.context_processors_data['csrf_token']
return {
'csrf_token': csrf_token,

View file

@ -20,7 +20,7 @@ Example:
```python
class Table(Component):
def get_context_data(self, *args, **attrs):
def get_template_data(self, args, kwargs, slots, context):
# Access component's ID
assert self.id == "c1A2b3c"
@ -77,7 +77,7 @@ If you need to expand this limit, please open an issue on GitHub.
```python
class Table(Component):
def get_context_data(self, *args, **attrs):
def get_template_data(self, args, kwargs, slots, context):
# Access component's ID
assert self.id == "c1A2b3c"
@ -102,7 +102,7 @@ to access the positional and keyword arguments passed to [`Component.render()`](
```python
class Table(Component):
def get_context_data(self, *args, **kwargs):
def get_template_data(self, args, kwargs, slots, context):
# Access component's inputs, slots and context
assert self.input.args == [123, "str"]
assert self.input.kwargs == {"variable": "test", "another": 1}
@ -140,7 +140,7 @@ Read more about the request object and context processors in the [HTTP Request](
from django.http import HttpRequest
class Table(Component):
def get_context_data(self, *args, **attrs):
def get_template_data(self, args, kwargs, slots, context):
# Access the request object and Django's context processors
assert self.request.GET == {"query": "something"}
assert self.context_processors_data['user'].username == "admin"
@ -166,7 +166,7 @@ Read more about [Provide / Inject](../advanced/provide_inject.md).
```python
class Table(Component):
def get_context_data(self, *args, **attrs):
def get_template_data(self, args, kwargs, slots, context):
# Access provided data
data = self.inject("some_data")
assert data.some_data == "some_data"

View file

@ -30,9 +30,9 @@ from django_components import Component, register, types
@register("calendar")
class Calendar(Component):
def get_context_data(self, date):
def get_template_data(self, args, kwargs, slots, context):
return {
"date": date,
"date": kwargs["date"],
}
template: types.django_html = """
@ -114,9 +114,9 @@ from django_components import Component, register, types
@register("calendar")
class Calendar(Component):
def get_context_data(self, date):
def get_template_data(self, args, kwargs, slots, context):
return {
"date": date,
"date": kwargs["date"],
}
template: types.django_html = """
@ -155,9 +155,9 @@ from django_components import Component, register
@register("calendar")
class Calendar(Component):
def get_context_data(self, date):
def get_template_data(self, args, kwargs, slots, context):
return {
"date": date,
"date": kwargs["date"],
}
# language=HTML

View file

@ -165,8 +165,8 @@ like so:
```py
class MyTable(Component):
def get_context_data(self, *args, **kwargs):
default_slot = self.input.slots["default"]
def get_template_data(self, args, kwargs, slots, context):
default_slot = slots["default"]
return {
"default_slot": default_slot,
}
@ -475,8 +475,8 @@ class MyComp(Component):
</div>
"""
def get_context_data(self, input):
processed_input = do_something(input)
def get_template_data(self, args, kwargs, slots, context):
processed_input = do_something(kwargs["input"])
return {"input": processed_input}
```
@ -504,8 +504,8 @@ class MyComp(Component):
</div>
"""
def get_context_data(self, input):
processed_input = do_something(input)
def get_template_data(self, args, kwargs, slots, context):
processed_input = do_something(kwargs["input"])
return {
"input": processed_input,
}
@ -646,9 +646,9 @@ You can dynamically pass all slots to a child component. This is similar to
```djc_py
class MyTable(Component):
def get_context_data(self, *args, **kwargs):
def get_template_data(self, args, kwargs, slots, context):
return {
"slots": self.input.slots,
"slots": slots,
}
template = """

View file

@ -100,7 +100,7 @@ class BaseForm(Component):
</form>
"""
def get_context_data(self, **kwargs):
def get_template_data(self, args, kwargs, slots, context):
return {
"form_content": self.get_form_content(),
"submit_text": "Submit"
@ -112,8 +112,8 @@ class BaseForm(Component):
class ContactForm(BaseForm):
# Extend parent's "context"
# but override "submit_text"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
def get_template_data(self, args, kwargs, slots, context):
context = super().get_template_data(args, kwargs, slots, context)
context["submit_text"] = "Send Message"
return context

View file

@ -30,14 +30,12 @@ so are still valid:
</body>
```
These can then be accessed inside `get_context_data` so:
These can then be accessed inside `get_template_data` so:
```py
@register("calendar")
class Calendar(Component):
# Since # . @ - are not valid identifiers, we have to
# use `**kwargs` so the method can accept these args.
def get_context_data(self, **kwargs):
def get_template_data(self, args, kwargs, slots, context):
return {
"date": kwargs["my-date"],
"id": kwargs["#some_id"],
@ -92,17 +90,17 @@ _New in version 0.93_
When passing data around, sometimes you may need to do light transformations, like negating booleans or filtering lists.
Normally, what you would have to do is to define ALL the variables
inside `get_context_data()`. But this can get messy if your components contain a lot of logic.
inside `get_template_data()`. But this can get messy if your components contain a lot of logic.
```py
@register("calendar")
class Calendar(Component):
def get_context_data(self, id: str, editable: bool):
def get_template_data(self, args, kwargs, slots, context):
return {
"editable": editable,
"readonly": not editable,
"input_id": f"input-{id}",
"icon_id": f"icon-{id}",
"editable": kwargs["editable"],
"readonly": not kwargs["editable"],
"input_id": f"input-{kwargs['id']}",
"icon_id": f"icon-{kwargs['id']}",
...
}
```
@ -200,10 +198,10 @@ class MyComp(Component):
{% component "other" attrs=attrs / %}
"""
def get_context_data(self, some_id: str):
def get_template_data(self, args, kwargs, slots, context):
attrs = {
"class": "pa-4 flex",
"data-some-id": some_id,
"data-some-id": kwargs["some_id"],
"@click.stop": "onClickHandler",
}
return {"attrs": attrs}
@ -231,8 +229,8 @@ class MyComp(Component):
/ %}
"""
def get_context_data(self, some_id: str):
return {"some_id": some_id}
def get_template_data(self, args, kwargs, slots, context):
return {"some_id": kwargs["some_id"]}
```
Sweet! Now all the relevant HTML is inside the template, and we can move it to a separate file with confidence:

View file

@ -184,7 +184,7 @@ class Calendar(Component):
js_file = "calendar.js" # <--- new
css_file = "calendar.css" # <--- new
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"date": "1970-01-01",
}
@ -256,7 +256,7 @@ class Calendar(Component):
"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css", # Tailwind
]
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"date": "1970-01-01",
}

View file

@ -158,7 +158,7 @@ the to `2024-12-14`, which is Saturday, our template from previous step would re
The first instance rendered `2024-12-16`, while the rest rendered `2024-12-14`!
Why? Remember that in the [`get_context_data()`](../../reference/api#django_components.Component.get_context_data)
Why? Remember that in the [`get_template_data()`](../../reference/api#django_components.Component.get_template_data)
method of our Calendar component, we pre-process the date. If the date falls on Saturday or Sunday, we shift it to next Monday:
```python title="[project root]/components/calendar/calendar.py"
@ -174,11 +174,11 @@ def to_workweek_date(d: date):
class Calendar(Component):
template_file = "calendar.html"
...
def get_context_data(self, date: date, extra_class: str | None = None):
workweek_date = to_workweek_date(date)
def get_template_data(self, args, kwargs, slots, context):
workweek_date = to_workweek_date(kwargs["date"])
return {
"date": workweek_date,
"extra_class": extra_class,
"extra_class": kwargs.get("extra_class", "text-blue"),
}
```
@ -284,7 +284,7 @@ each time:
Generally, slots are more flexible - you can access the slot data, even the original slot content.
Thus, slots behave more like functions that render content based on their context.
On the other hand, variables are static - the variable you pass to a component is what will be used.
On the other hand, variables are simpler - the variable you pass to a component is what will be used.
Moreover, slots are treated as part of the template - for example the CSS scoping (work in progress)
is applied to the slot content too.

View file

@ -30,7 +30,7 @@ class Calendar(Component):
js_file = "calendar.js"
css_file = "calendar.css"
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"date": "1970-01-01",
}

View file

@ -10,7 +10,7 @@ What we want is to be able to use the Calendar component within the template lik
### 1. Understading component inputs
In section [Create your first component](../your_first_component), we defined
the [`get_context_data()`](../../reference/api#django_components.Component.get_context_data) method
the [`get_template_data()`](../../reference/api#django_components.Component.get_template_data) method
that defines what variables will be available within the template:
```python title="[project root]/components/calendar/calendar.py"
@ -20,13 +20,13 @@ from django_components import Component, register
class Calendar(Component):
template_file = "calendar.html"
...
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"date": "1970-01-01",
}
```
What we didn't say is that [`get_context_data()`](../../reference/api#django_components.Component.get_context_data)
What we didn't say is that [`get_template_data()`](../../reference/api#django_components.Component.get_template_data)
actually receives the args and kwargs that were passed to a component.
So if we call a component with a `date` and `extra_class` keywords:
@ -38,7 +38,10 @@ So if we call a component with a `date` and `extra_class` keywords:
This is the same as calling:
```py
Calendar.get_context_data(date="2024-12-13", extra_class="text-red")
Calendar.get_template_data(
args=[],
kwargs={"date": "2024-12-13", "extra_class": "text-red"},
)
```
And same applies to positional arguments, or mixing args and kwargs, where:
@ -50,13 +53,16 @@ And same applies to positional arguments, or mixing args and kwargs, where:
is same as
```py
Calendar.get_context_data("2024-12-13", extra_class="text-red")
Calendar.get_template_data(
args=["2024-12-13"],
kwargs={"extra_class": "text-red"},
)
```
### 2. Define inputs for `get_context_data`
### 2. Define inputs
Let's put this to test. We want to pass `date` and `extra_class` kwargs to the component.
And so, we can write the [`get_context_data()`](../../reference/api#django_components.Component.get_context_data)
And so, we can write the [`get_template_data()`](../../reference/api#django_components.Component.get_template_data)
method such that it expects those parameters:
```python title="[project root]/components/calendar/calendar.py"
@ -68,46 +74,40 @@ from django_components import Component, register
class Calendar(Component):
template_file = "calendar.html"
...
def get_context_data(self, date: date, extra_class: str = "text-blue"):
def get_template_data(self, args, kwargs, slots, context):
return {
"date": date,
"extra_class": extra_class,
"date": kwargs["date"],
"extra_class": kwargs.get("extra_class", "text-blue"),
}
```
!!! info
Since [`get_context_data()`](../../reference/api#django_components.Component.get_context_data)
is just a regular Python function, type hints annotations work the same way as anywhere else.
!!! warning
Since [`get_context_data()`](../../reference/api#django_components.Component.get_context_data)
is just a regular Python function, it will raise TypeError if it receives incorrect parameters.
Since `extra_class` is optional in the function signature, it's optional also in the template.
So both following calls are valid:
```htmldjango
{% component "calendar" "2024-12-13" / %}
{% component "calendar" "2024-12-13" extra_class="text-red" / %}
{% component "calendar" date="2024-12-13" / %}
{% component "calendar" date="2024-12-13" extra_class="text-red" / %}
```
However, `date` is required. Thus we MUST provide it. Same with regular Python functions,
`date` can be set either as positional or keyword argument. But either way it MUST be set:
!!! warning
```htmldjango
{% component "calendar" "2024-12-13" / %}
{% component "calendar" extra_class="text-red" date="2024-12-13" / %}
[`get_template_data()`](../../reference/api#django_components.Component.get_template_data)
differentiates between positional and keyword arguments,
so you have to make sure to pass the arguments correctly.
{% component "calendar" extra_class="text-red" / %}
```
Since `date` is expected to be a keyword argument, it MUST be provided as such:
### 3. Process inputs in `get_context_data`
```htmldjango
`date` is kwarg
{% component "calendar" date="2024-12-13" / %}
The [`get_context_data()`](../../reference/api#django_components.Component.get_context_data)
`date` is arg
{% component "calendar" "2024-12-13" / %}
```
### 3. Process inputs
The [`get_template_data()`](../../reference/api#django_components.Component.get_template_data)
method is powerful, because it allows us to decouple
component inputs from the template variables. In other words, we can pre-process
the component inputs, and massage them into a shape that's most appropriate for
@ -160,12 +160,14 @@ cities_by_pop = [
]
```
Without the `get_context_data()` method, we'd have to either:
Without the [`get_template_data()`](../../reference/api#django_components.Component.get_template_data) method,
we'd have to either:
1. Pre-process the data in Python before passing it to the components.
2. Define a Django filter or template tag to take the data and process it on the spot.
Instead, with `get_context_data()`, we can keep this transformation private to this component,
Instead, with [`get_template_data()`](../../reference/api#django_components.Component.get_template_data),
we can keep this transformation private to this component,
and keep the rest of the codebase clean.
```py
@ -176,13 +178,14 @@ def group_by_pop(data):
class PopulationTable(Component):
template_file = "population_table.html"
def get_context_data(self, data):
def get_template_data(self, args, kwargs, slots, context):
return {
"data": group_by_pop(data),
"data": group_by_pop(kwargs["data"]),
}
```
Similarly we can make use of `get_context_data()` to pre-process the date that was given to the component:
Similarly we can make use of [`get_template_data()`](../../reference/api#django_components.Component.get_template_data)
to pre-process the date that was given to the component:
```python title="[project root]/components/calendar/calendar.py"
from datetime import date
@ -197,17 +200,17 @@ def to_workweek_date(d: date):
class Calendar(Component):
template_file = "calendar.html"
...
def get_context_data(self, date: date, extra_class: str = "text-blue"):
workweek_date = to_workweek_date(date) # <--- new
def get_template_data(self, args, kwargs, slots, context):
workweek_date = to_workweek_date(kwargs["date"]) # <--- new
return {
"date": workweek_date, # <--- changed
"extra_class": extra_class,
"extra_class": kwargs.get("extra_class", "text-blue"),
}
```
### 4. Pass inputs to components
Once we're happy with `Calendar.get_contex_data()`, we can update our templates to use
Once we're happy with `Calendar.get_template_data()`, we can update our templates to use
the parametrized version of the component:
```htmldjango
@ -224,7 +227,7 @@ Next, you will learn [how to use slots give your components even more flexibilit
### 5. Add defaults
In our example, we've set the `extra_class` to default to `"text-blue"` by setting it in the
[`get_context_data()`](../../reference/api#django_components.Component.get_context_data)
[`get_template_data()`](../../reference/api#django_components.Component.get_template_data)
method.
However, you may want to use the same default value in multiple methods, like
@ -248,10 +251,10 @@ class Calendar(Component):
class Defaults: # <--- new
extra_class = "text-blue"
def get_context_data(self, date: date, extra_class: str): # <--- changed
workweek_date = to_workweek_date(date)
def get_template_data(self, args, kwargs, slots, context):
workweek_date = to_workweek_date(kwargs["date"])
return {
"date": workweek_date,
"extra_class": extra_class,
"extra_class": kwargs["extra_class"], # <--- changed
}
```

View file

@ -19,7 +19,7 @@ class Calendar(Component):
js_file = "calendar.js"
css_file = "calendar.css"
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"date": "1970-01-01",
}

View file

@ -104,7 +104,7 @@ Inside `calendar.html`, write:
```
In this example we've defined one template variable `date`. You can use any and as many variables as you like. These variables will be
defined in the Python file in [`get_context_data()`](../../reference/api#django_components.Component.get_context_data)
defined in the Python file in [`get_template_data()`](../../reference/api#django_components.Component.get_template_data)
when creating an instance of this component.
!!! note
@ -142,7 +142,7 @@ class Calendar(Component):
In `calendar.html`, we've used the variable `date`. So we need to define it for the template to work.
This is done using [`Component.get_context_data()`](../../reference/api#django_components.Component.get_context_data).
This is done using [`Component.get_template_data()`](../../reference/api#django_components.Component.get_template_data).
It's a function that returns a dictionary. The entries in this dictionary
will become available within the template as variables, e.g. as `{{ date }}`.
@ -152,7 +152,7 @@ from django_components import Component
class Calendar(Component):
template_file = "calendar.html"
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"date": "1970-01-01",
}

View file

@ -246,6 +246,6 @@ Instead, our solution is closer to [how Vue handles slots](https://vuejs.org/gui
While we do not wrap the logic in a function, we do PREPARE IN ADVANCE:
1. The content that should be rendered for each slot
2. The context variables from `get_context_data()`
2. The context variables from `get_template_data()`
Thus, once we reach the `{% slot %}` node, in it's `render()` method, we access the data above, and, depending on the `context_behavior` setting, include the current context or not. For more info, see `SlotNode.render()`.

View file

@ -53,8 +53,8 @@ class Calendar(Component):
js_file = "calendar.js"
css_file = "calendar.css"
def get_context_data(self, date):
return {"date": date}
def get_template_data(self, args, kwargs, slots, context):
return {"date": kwargs["date"]}
```
Use the component like this:
@ -115,9 +115,9 @@ class Calendar(Component):
css = ["bootstrap/dist/css/bootstrap.min.css"]
# Variables available in the template
def get_context_data(self, date):
def get_template_data(self, args, kwargs, slots, context):
return {
"date": date
"date": kwargs["date"]
}
```
@ -222,7 +222,7 @@ class Table(Component):
</div>
"""
def get_context_data(self, var1, var2, variable, another, **attrs):
def get_template_data(self, args, kwargs, slots, context):
# Access component's ID
assert self.id == "djc1A2b3c"
@ -237,7 +237,7 @@ class Table(Component):
assert self.context_processors_data['user'].username == "admin"
return {
"variable": variable,
"variable": kwargs["variable"],
}
# Access component's HTML / JS / CSS
@ -337,9 +337,9 @@ class Calendar(Component):
},
)
def get_context_data(self, page):
def get_template_data(self, args, kwargs, slots, context):
return {
"page": page,
"page": kwargs["page"],
}
# Get auto-generated URL for the component
@ -371,7 +371,7 @@ Read more about [Provide / Inject](https://django-components.github.io/django-co
class Header(Component):
template = "..."
def get_context_data(self, *args, **kwargs):
def get_template_data(self, args, kwargs, slots, context):
theme = self.inject("theme").variant
return {
"theme": theme,

View file

@ -67,7 +67,7 @@ If you insert this tag multiple times, ALL JS scripts will be duplicately insert
<a href="https://github.com/django-components/django-components/tree/master/src/django_components/templatetags/component_tags.py#L2794" target="_blank">See source code</a>
<a href="https://github.com/django-components/django-components/tree/master/src/django_components/templatetags/component_tags.py#L2772" target="_blank">See source code</a>
@ -363,9 +363,9 @@ class Parent(Component):
</div>
"""
def get_context_data(self, user: User):
def get_template_data(self, args, kwargs, slots, context):
return {
"user": user,
"user": kwargs["user"],
}
```
@ -381,7 +381,7 @@ class Child(Component):
</div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
user = self.inject("user_data").user
return {
"user": user,