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

@ -63,8 +63,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:
@ -125,9 +125,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"]
}
```
@ -232,7 +232,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"
@ -247,7 +247,7 @@ class Table(Component):
assert self.context_processors_data['user'].username == "admin"
return {
"variable": variable,
"variable": kwargs["variable"],
}
# Access component's HTML / JS / CSS
@ -347,9 +347,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
@ -381,7 +381,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

@ -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,

View file

@ -1,3 +1,5 @@
from typing import NamedTuple
from django_components import Component, register
@ -13,9 +15,12 @@ class Calendar(Component):
js_file = "calendar/calendar.js"
# This component takes one parameter, a date string to show in the template
def get_context_data(self, date):
class Kwargs(NamedTuple):
date: str
def get_template_data(self, args, kwargs: Kwargs, slots, context):
return {
"date": date,
"date": kwargs.date,
}
class View:
@ -41,9 +46,12 @@ class CalendarRelative(Component):
js_file = "calendar.js"
# This component takes one parameter, a date string to show in the template
def get_context_data(self, date):
class Kwargs(NamedTuple):
date: str
def get_template_data(self, args, kwargs: Kwargs, slots, context):
return {
"date": date,
"date": kwargs.date,
}
class View:

View file

@ -1,24 +1,8 @@
from typing import Any, Dict
from django_components import Component, register, types
@register("greeting")
class Greeting(Component):
class View:
def get(self, request, *args, **kwargs):
slots = {"message": "Hello, world!"}
return Greeting.render_to_response(
request=request,
slots=slots,
kwargs={
"name": request.GET.get("name", ""),
},
)
def get_context_data(self, name, *args, **kwargs) -> Dict[str, Any]:
return {"name": name}
template: types.django_html = """
<div id="greeting">Hello, {{ name }}!</div>
{% slot "message" %}{% endslot %}
@ -37,3 +21,17 @@ class Greeting(Component):
alert("Hello!");
});
"""
def get_template_data(self, args, kwargs, slots, context):
return {"name": kwargs["name"]}
class View:
def get(self, request, *args, **kwargs):
slots = {"message": "Hello, world!"}
return Greeting.render_to_response(
request=request,
slots=slots,
kwargs={
"name": request.GET.get("name", ""),
},
)

View file

@ -1,3 +1,5 @@
from typing import NamedTuple
from django_components import Component, register
@ -13,9 +15,12 @@ class CalendarNested(Component):
js_file = "calendar.js"
# This component takes one parameter, a date string to show in the template
def get_context_data(self, date):
class Kwargs(NamedTuple):
date: str
def get_template_data(self, args, kwargs: Kwargs, slots, context):
return {
"date": date,
"date": kwargs.date,
}
class View:

View file

@ -1,27 +1,11 @@
import time
from typing import Any, Dict
from typing import NamedTuple
from django_components import Component, register, types
@register("recursive")
class Recursive(Component):
class View:
def get(self, request):
time_before = time.time()
output = Recursive.render_to_response(
request=request,
kwargs={
"depth": 0,
},
)
time_after = time.time()
print("TIME: ", time_after - time_before)
return output
def get_context_data(self, depth: int = 0) -> Dict[str, Any]:
return {"depth": depth + 1}
template: types.django_html = """
<div id="recursive">
depth: {{ depth }}
@ -31,3 +15,25 @@ class Recursive(Component):
{% endif %}
</div>
"""
class Kwargs(NamedTuple):
depth: int
class Defaults:
depth = 0
def get_template_data(self, args, kwargs: Kwargs, slots, context):
return {"depth": kwargs.depth + 1}
class View:
def get(self, request):
time_before = time.time()
output = Recursive.render_to_response(
request=request,
kwargs=Recursive.Kwargs(
depth=0,
),
)
time_after = time.time()
print("TIME: ", time_after - time_before)
return output

View file

@ -56,7 +56,7 @@ class ContextBehavior(str, Enum):
That is, they enrich the context, and pass it along.
1. Component fills use the context of the component they are within.
2. Variables from [`Component.get_context_data()`](../api#django_components.Component.get_context_data)
2. Variables from [`Component.get_template_data()`](../api#django_components.Component.get_template_data)
are available to the component fill.
**Example:**
@ -71,7 +71,7 @@ class ContextBehavior(str, Enum):
{% endwith %}
```
and this context returned from the `Component.get_context_data()` method
and this context returned from the `Component.get_template_data()` method
```python
{ "my_var": 123 }
```
@ -98,7 +98,7 @@ class ContextBehavior(str, Enum):
"""
This setting makes the component fills behave similar to Vue or React, where
the fills use EXCLUSIVELY the context variables defined in
[`Component.get_context_data()`](../api#django_components.Component.get_context_data).
[`Component.get_template_data()`](../api#django_components.Component.get_template_data).
**Example:**
@ -112,7 +112,7 @@ class ContextBehavior(str, Enum):
{% endwith %}
```
and this context returned from the `get_context_data()` method
and this context returned from the `get_template_data()` method
```python
{ "my_var": 123 }
```

View file

@ -199,16 +199,20 @@ class CreateCommand(ComponentCommand):
@register("{name}")
class {name.capitalize()}(Component):
template_file = "{name}/{template_filename}"
template_file = "{template_filename}"
js_file = "{js_filename}"
css_file = "{css_filename}"
def get_context_data(self, value):
class Kwargs(NamedTuple):
param: str
class Defaults:
param = "sample value"
def get_template_data(self, args, kwargs: Kwargs, slots, context):
return {{
"param": "sample value",
"param": kwargs.param,
}}
class Media:
css = "{name}/{css_filename}"
js = "{name}/{js_filename}"
"""
)
f.write(py_content.strip())

View file

@ -231,9 +231,9 @@ class ComponentVars(NamedTuple):
```py
class MyTable(Component):
def get_context_data(self, *args, **kwargs):
def get_template_data(self, args, kwargs, slots, context):
return {
"my_slot_filled": "my_slot" in self.input.slots
"my_slot_filled": "my_slot" in slots
}
```
"""
@ -508,7 +508,7 @@ class Component(metaclass=ComponentMeta):
class MyComponent(Component):
template_file = "path/to/template.html"
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {"name": "World"}
```
"""
@ -556,7 +556,7 @@ class Component(metaclass=ComponentMeta):
class MyComponent(Component):
template = "Hello, {{ name }}!"
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {"name": "World"}
```
"""
@ -1663,7 +1663,7 @@ class Component(metaclass=ComponentMeta):
```py
class MyComponent(Component):
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
print(f"Rendering '{self.id}'")
return {}
@ -1702,14 +1702,9 @@ class Component(metaclass=ComponentMeta):
**Example:**
Use can use [`self.input.args`](../api/#django_components.ComponentInput.args)
and [`self.input.kwargs`](../api/#django_components.ComponentInput.kwargs)
to access the positional and keyword arguments passed to
[`Component.render()`](../api/#django_components.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}
@ -1778,7 +1773,7 @@ class Component(metaclass=ComponentMeta):
```py
class MyComponent(Component):
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
user_id = self.request.GET['user_id']
return {
'user_id': user_id,
@ -1801,7 +1796,7 @@ class Component(metaclass=ComponentMeta):
This data is also available from within the component's template, without having to
return this data from
[`get_context_data()`](../api#django_components.Component.get_context_data).
[`get_template_data()`](../api#django_components.Component.get_template_data).
In regular Django templates, you need to use
[`RequestContext`](https://docs.djangoproject.com/en/5.1/ref/templates/api/#django.template.RequestContext)
@ -1831,7 +1826,7 @@ class Component(metaclass=ComponentMeta):
```py
class MyComponent(Component):
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
user = self.context_processors_data['user']
return {
'is_logged_in': user.is_authenticated,
@ -2371,7 +2366,7 @@ class Component(metaclass=ComponentMeta):
# By adding the current input to the stack, we temporarily allow users
# to access the provided context, slots, etc. Also required so users can
# call `self.inject()` from within `get_context_data()`.
# call `self.inject()` from within `get_template_data()`.
#
# This is handled as a stack, as users can potentially call `component.render()`
# from within component hooks. Thus, then they do so, `component.id` will be the ID

View file

@ -539,7 +539,7 @@ def _resolve_media(comp_cls: Type["Component"], comp_media: ComponentMedia) -> N
class MyComponent(Component):
media_class = MyMedia
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
assert isinstance(self.media, MyMedia)
```
"""

View file

@ -99,13 +99,14 @@ class DynamicComponent(Component):
_is_dynamic_component = True
def get_context_data(
def get_template_data(
self,
*args: Any,
registry: Optional[ComponentRegistry] = None,
**kwargs: Any,
args: Any,
kwargs: Any,
slots: Any,
context: Any,
) -> Dict:
# NOTE: We have to access `is` via kwargs, because it's a special keyword in Python
registry: Optional[ComponentRegistry] = kwargs.pop("registry", None)
comp_name_or_class: Union[str, Type[Component]] = kwargs.pop("is", None)
if not comp_name_or_class:
raise TypeError(f"Component '{self.name}' is missing a required argument 'is'")

View file

@ -172,7 +172,7 @@ class ComponentExtension:
class MyExtension:
...
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"my_extension": self.my_extension.do_something(),
}
@ -212,7 +212,7 @@ class ComponentExtension:
class MyExtension:
...
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"my_extension": self.my_extension.do_something(),
}
@ -450,7 +450,7 @@ class ComponentExtension:
Use this hook to modify or validate component inputs before they're processed.
This is the first hook that is called when rendering a component. As such this hook is called before
[`Component.get_context_data()`](../api#django_components.Component.get_context_data),
[`Component.get_template_data()`](../api#django_components.Component.get_template_data),
[`Component.get_js_data()`](../api#django_components.Component.get_js_data),
and [`Component.get_css_data()`](../api#django_components.Component.get_css_data) methods,
and the
@ -482,7 +482,7 @@ class ComponentExtension:
after a component's context and data methods have been processed.
This hook is called after
[`Component.get_context_data()`](../api#django_components.Component.get_context_data),
[`Component.get_template_data()`](../api#django_components.Component.get_template_data),
[`Component.get_js_data()`](../api#django_components.Component.get_js_data)
and [`Component.get_css_data()`](../api#django_components.Component.get_css_data).
@ -498,7 +498,7 @@ class ComponentExtension:
class MyExtension(ComponentExtension):
def on_component_data(self, ctx: OnComponentDataContext) -> None:
# Add extra template variable to all components when they are rendered
ctx.context_data["my_template_var"] = "my_value"
ctx.template_data["my_template_var"] = "my_value"
```
"""
pass

View file

@ -100,9 +100,9 @@ class NodeMeta(type):
#
# ```py
# class MyComponent(Component):
# def get_context_data(self, name: str, **kwargs: Any) -> str:
# def get_template_data(self, args, kwargs, slots, context) -> str:
# return {
# "name": name,
# "name": kwargs.pop("name"),
# "attrs": kwargs,
# }
# template = """

View file

@ -41,9 +41,9 @@ class ProvideNode(BaseNode):
</div>
\"\"\"
def get_context_data(self, user: User):
def get_template_data(self, args, kwargs, slots, context):
return {
"user": user,
"user": kwargs["user"],
}
```
@ -59,7 +59,7 @@ class ProvideNode(BaseNode):
</div>
\"\"\"
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
user = self.inject("user_data").user
return {
"user": user,
@ -138,7 +138,7 @@ def set_provided_context_var(
) -> str:
"""
'Provide' given data under given key. In other words, this data can be retrieved
using `self.inject(key)` inside of `get_context_data()` method of components that
using `self.inject(key)` inside of `get_template_data()` method of components that
are nested inside the `{% provide %}` tag.
"""
# NOTE: We raise TemplateSyntaxError since this func should be called only from

View file

@ -1083,8 +1083,8 @@ def _nodelist_to_slot_render_func(
#
# And so we want to put the `extra_context` into the same layer that contains `_COMPONENT_CONTEXT_KEY`.
#
# HOWEVER, the layer with `_COMPONENT_CONTEXT_KEY` also contains user-defined data from `get_context_data()`.
# Data from `get_context_data()` should take precedence over `extra_context`. So we have to insert
# HOWEVER, the layer with `_COMPONENT_CONTEXT_KEY` also contains user-defined data from `get_template_data()`.
# Data from `get_template_data()` should take precedence over `extra_context`. So we have to insert
# the forloop variables BEFORE that.
index_of_last_component_layer = get_last_index(ctx.dicts, lambda d: _COMPONENT_CONTEXT_KEY in d)
if index_of_last_component_layer is None:
@ -1096,8 +1096,8 @@ def _nodelist_to_slot_render_func(
# the following line can be removed.
index_of_last_component_layer -= 1
# Insert the `extra_context` layer BEFORE the layer that defines the variables from get_context_data.
# Thus, get_context_data will overshadow these on conflict.
# Insert the `extra_context` layer BEFORE the layer that defines the variables from get_template_data.
# Thus, get_template_data will overshadow these on conflict.
ctx.dicts.insert(index_of_last_component_layer, extra_context or {})
trace_component_msg("RENDER_NODELIST", component_name, component_id=None, slot_name=slot_name)

View file

@ -23,5 +23,5 @@ class MultFileComponent(Component):
kwargs={"variable": "GET"},
)
def get_context_data(self, variable, *args, **kwargs) -> Dict[str, Any]:
return {"variable": variable}
def get_template_data(self, args, kwargs, slots, context) -> Dict[str, Any]:
return {"variable": kwargs["variable"]}

View file

@ -27,5 +27,5 @@ class RelativeFileComponent(Component):
kwargs={"variable": "GET"},
)
def get_context_data(self, variable, *args, **kwargs) -> Dict[str, Any]:
return {"variable": variable}
def get_template_data(self, args, kwargs, slots, context) -> Dict[str, Any]:
return {"variable": kwargs["variable"]}

View file

@ -32,5 +32,5 @@ class RelativeFileWithPathObjComponent(Component):
js = PathObj("relative_file_pathobj.js")
css = PathObj("relative_file_pathobj.css")
def get_context_data(self, variable, *args, **kwargs) -> Dict[str, Any]:
return {"variable": variable}
def get_template_data(self, args, kwargs, slots, context) -> Dict[str, Any]:
return {"variable": kwargs["variable"]}

View file

@ -29,5 +29,5 @@ class SingleFileComponent(Component):
kwargs={"variable": "GET"},
)
def get_context_data(self, variable, *args, **kwargs) -> Dict[str, Any]:
return {"variable": variable}
def get_template_data(self, args, kwargs, slots, context) -> Dict[str, Any]:
return {"variable": kwargs["variable"]}

View file

@ -12,5 +12,5 @@ class RelativeFileWithPathObjComponent(Component):
js = "staticfiles.js"
css = "staticfiles.css"
def get_context_data(self, variable, *args, **kwargs) -> Dict[str, Any]:
return {"variable": variable}
def get_template_data(self, args, kwargs, slots, context) -> Dict[str, Any]:
return {"variable": kwargs["variable"]}

View file

@ -17,10 +17,13 @@ class SimpleComponent(Component):
globalThis.testSimpleComponent = 'kapowww!'
"""
def get_context_data(self, variable, variable2="default"):
class Defaults:
variable2 = "default"
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": variable,
"variable2": variable2,
"variable": kwargs["variable"],
"variable2": kwargs["variable2"],
}
class Media:
@ -48,8 +51,8 @@ class SimpleComponentNested(Component):
globalThis.testSimpleComponentNested = 'bongo!'
"""
def get_context_data(self, variable):
return {"variable": variable}
def get_template_data(self, args, kwargs, slots, context):
return {"variable": kwargs["variable"]}
class Media:
css = ["style.css", "style2.css"]
@ -72,8 +75,8 @@ class OtherComponent(Component):
globalThis.testOtherComponent = 'wowzee!'
"""
def get_context_data(self, variable):
return {"variable": variable}
def get_template_data(self, args, kwargs, slots, context):
return {"variable": kwargs["variable"]}
class Media:
css = "style.css"

View file

@ -1,4 +1,4 @@
from typing import Any, Dict, Optional
from typing import Optional
from django_components import Component, register
@ -14,5 +14,5 @@ class AppLvlCompComponent(Component):
js = "app_lvl_comp.js"
css = "app_lvl_comp.css"
def get_context_data(self, variable, *args, **kwargs) -> Dict[str, Any]:
return {"variable": variable}
def get_template_data(self, args, kwargs, slots, context):
return {"variable": kwargs["variable"]}

View file

@ -1,5 +1,3 @@
from typing import Any, Dict
from django_components import Component, register
@ -12,5 +10,5 @@ class AppLvlCompComponent(Component):
js = "app_lvl_comp.js"
css = "app_lvl_comp.css"
def get_context_data(self, variable, *args, **kwargs) -> Dict[str, Any]:
return {"variable": variable}
def get_template_data(self, args, kwargs, slots, context):
return {"variable": kwargs["variable"]}

View file

@ -1,5 +1,3 @@
from typing import Any, Dict
from django_components import Component, register
@ -10,5 +8,5 @@ class AppLvlCompComponent(Component):
{{ variable }}
"""
def get_context_data(self, variable, *args, **kwargs) -> Dict[str, Any]:
return {"variable": variable}
def get_template_data(self, args, kwargs, slots, context):
return {"variable": kwargs["variable"]}

View file

@ -144,9 +144,9 @@ class TestHtmlAttrs:
</div>
""" # noqa: E501
def get_context_data(self, *args, attrs):
def get_template_data(self, args, kwargs, slots, context):
return {
"attrs": attrs,
"attrs": kwargs["attrs"],
"defaults": {"class": "override-me"},
}
@ -172,9 +172,9 @@ class TestHtmlAttrs:
</div>
""" # noqa: E501
def get_context_data(self, *args, attrs):
def get_template_data(self, args, kwargs, slots, context):
return {
"attrs": attrs,
"attrs": kwargs["attrs"],
"defaults": {"class": "override-me"},
"class": "123 457",
}
@ -197,9 +197,9 @@ class TestHtmlAttrs:
</div>
""" # noqa: E501
def get_context_data(self, *args, attrs):
def get_template_data(self, args, kwargs, slots, context):
return {
"attrs": attrs,
"attrs": kwargs["attrs"],
"defaults": {"class": "override-me"},
}
@ -225,9 +225,9 @@ class TestHtmlAttrs:
</div>
""" # noqa: E501
def get_context_data(self, *args, attrs):
def get_template_data(self, args, kwargs, slots, context):
return {
"attrs": attrs,
"attrs": kwargs["attrs"],
"defaults": {"class": "override-me"},
}
@ -253,10 +253,10 @@ class TestHtmlAttrs:
</div>
""" # noqa: E501
def get_context_data(self, *args, attrs):
def get_template_data(self, args, kwargs, slots, context):
return {
"props": {
"attrs": attrs,
"attrs": kwargs["attrs"],
"defaults": {"class": "override-me"},
"class": "added_class",
"data-id": 123,
@ -285,8 +285,8 @@ class TestHtmlAttrs:
</div>
""" # noqa: E501
def get_context_data(self, *args, attrs):
return {"attrs": attrs}
def get_template_data(self, args, kwargs, slots, context):
return {"attrs": kwargs["attrs"]}
template = Template(self.template_str)
rendered = template.render(Context({"class_var": "padding-top-8"}))
@ -318,8 +318,8 @@ class TestHtmlAttrs:
</div>
""" # noqa: E501
def get_context_data(self, *args, attrs):
return {"attrs": attrs}
def get_template_data(self, args, kwargs, slots, context):
return {"attrs": kwargs["attrs"]}
template = Template(self.template_str)
@ -346,8 +346,8 @@ class TestHtmlAttrs:
</div>
""" # noqa: E501
def get_context_data(self, *args, attrs):
return {"attrs": attrs}
def get_template_data(self, args, kwargs, slots, context):
return {"attrs": kwargs["attrs"]}
template = Template(self.template_str)
@ -367,8 +367,8 @@ class TestHtmlAttrs:
</div>
""" # noqa: E501
def get_context_data(self, *args, attrs):
return {"attrs": attrs}
def get_template_data(self, args, kwargs, slots, context):
return {"attrs": kwargs["attrs"]}
template = Template(self.template_str)
rendered = template.render(Context({"class_var": "padding-top-8"}))
@ -391,8 +391,8 @@ class TestHtmlAttrs:
</div>
""" # noqa: E501
def get_context_data(self, *args, attrs):
return {"attrs": attrs}
def get_template_data(self, args, kwargs, slots, context):
return {"attrs": kwargs["attrs"]}
template_str: types.django_html = """
{% load component_tags %}
@ -421,8 +421,8 @@ class TestHtmlAttrs:
</div>
""" # noqa: E501
def get_context_data(self, *args, attrs):
return {"attrs": attrs}
def get_template_data(self, args, kwargs, slots, context):
return {"attrs": kwargs["attrs"]}
template = Template(self.template_str)
rendered = template.render(Context({"class_var": "padding-top-8"}))
@ -446,9 +446,9 @@ class TestHtmlAttrs:
</div>
"""
def get_context_data(self, *args, attrs):
def get_template_data(self, args, kwargs, slots, context):
return {
"attrs": attrs,
"attrs": kwargs["attrs"],
"defaults": {"class": "override-me"},
}
@ -474,7 +474,7 @@ class TestHtmlAttrs:
</div>
"""
def get_context_data(self, *args, attrs):
def get_template_data(self, args, kwargs, slots, context):
return {
"attrs": None,
"defaults": None,

View file

@ -4,7 +4,7 @@ For tests focusing on the `component` tag, see `test_templatetags_component.py`
"""
import re
from typing import Any, Dict, no_type_check
from typing import Dict, no_type_check
import pytest
from django.conf import settings
@ -48,9 +48,9 @@ class CustomClient(Client):
super().__init__(*args, **kwargs)
# TODO_REMOVE_IN_V1 - Superseded by `self.get_template` in v1
@djc_test
class TestComponentOldTemplateApi:
class TestComponentLegacyApi:
# TODO_REMOVE_IN_V1 - Superseded by `self.get_template` in v1
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_get_template_string(self, components_settings):
class SimpleComponent(Component):
@ -60,6 +60,31 @@ class TestComponentOldTemplateApi:
"""
return content
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": kwargs.get("variable", None),
}
class Media:
css = "style.css"
js = "script.js"
rendered = SimpleComponent.render(kwargs={"variable": "test"})
assertHTMLEqual(
rendered,
"""
Variable: <strong data-djc-id-ca1bc3e>test</strong>
""",
)
# TODO_REMOVE_IN_V2 - `get_context_data()` was superseded by `self.get_template_data`
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_get_context_data(self, components_settings):
class SimpleComponent(Component):
template = """
Variable: <strong>{{ variable }}</strong>
"""
def get_context_data(self, variable=None):
return {
"variable": variable,
@ -95,9 +120,9 @@ class TestComponent:
Variable: <strong>{{ variable }}</strong>
"""
def get_context_data(self, variable=None):
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": variable,
"variable": kwargs.get("variable", None),
}
class Media:
@ -121,9 +146,9 @@ class TestComponent:
"""
return content
def get_context_data(self, variable=None):
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": variable,
"variable": kwargs.get("variable", None),
}
class Media:
@ -143,9 +168,9 @@ class TestComponent:
class SimpleComponent(Component):
template_file = "simple_template.html"
def get_context_data(self, variable=None):
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": variable,
"variable": kwargs.get("variable", None),
}
class Media:
@ -165,9 +190,9 @@ class TestComponent:
class SimpleComponent(Component):
template_name = "simple_template.html"
def get_context_data(self, variable=None):
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": variable,
"variable": kwargs.get("variable", None),
}
class Media:
@ -214,12 +239,12 @@ class TestComponent:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_template_file_dynamic(self, components_settings):
class SvgComponent(Component):
def get_context_data(self, name, css_class="", title="", **attrs):
def get_template_data(self, args, kwargs, slots, context):
return {
"name": name,
"css_class": css_class,
"title": title,
**attrs,
"name": kwargs.pop("name", None),
"css_class": kwargs.pop("css_class", None),
"title": kwargs.pop("title", None),
**kwargs,
}
def get_template_name(self, context):
@ -241,9 +266,9 @@ class TestComponent:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_allows_to_return_template(self, components_settings):
class TestComponent(Component):
def get_context_data(self, variable, **attrs):
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": variable,
"variable": kwargs.pop("variable", None),
}
def get_template(self, context):
@ -261,7 +286,7 @@ class TestComponent:
def test_input(self):
class TestComponent(Component):
@no_type_check
def get_context_data(self, var1, var2, variable, another, **attrs):
def get_template_data(self, args, kwargs, slots, context):
assert self.input.args == [123, "str"]
assert self.input.kwargs == {"variable": "test", "another": 1}
assert isinstance(self.input.context, Context)
@ -269,7 +294,7 @@ class TestComponent:
assert self.input.slots["my_slot"](Context(), None, None) == "MY_SLOT"
return {
"variable": variable,
"variable": kwargs["variable"],
}
@no_type_check
@ -312,15 +337,15 @@ class TestComponent:
</main>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
data = self.inject("my_provide")
data["data1"] # This should raise TypeError
return {"data": data}
@register("provider")
class Provider(Component):
def get_context_data(self, data: Any) -> Any:
return {"data": data}
def get_template_data(self, args, kwargs, slots, context):
return {"data": kwargs["data"]}
template: types.django_html = """
{% load component_tags %}
@ -331,8 +356,8 @@ class TestComponent:
@register("parent")
class Parent(Component):
def get_context_data(self, data: Any) -> Any:
return {"data": data}
def get_template_data(self, args, kwargs, slots, context):
return {"data": kwargs["data"]}
template: types.django_html = """
{% load component_tags %}
@ -387,7 +412,7 @@ class TestComponent:
class SimpleComponent(Component):
template = "Hello"
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return None
assert SimpleComponent.render() == "Hello"
@ -412,11 +437,11 @@ class TestComponentRender:
{% endslot %}
"""
def get_context_data(self, the_arg2=None, *args, the_kwarg=None, **kwargs):
def get_template_data(self, args, kwargs, slots, context):
return {
"the_arg2": the_arg2,
"the_kwarg": the_kwarg,
"args": args,
"the_arg2": args[0] if args else None,
"the_kwarg": kwargs.pop("the_kwarg", None),
"args": args[1:],
"kwargs": kwargs,
}
@ -425,7 +450,7 @@ class TestComponentRender:
rendered,
"""
the_arg2: None
args: ()
args: []
the_kwarg: None
kwargs: {}
---
@ -456,12 +481,12 @@ class TestComponentRender:
{% endslot %}
"""
def get_context_data(self, the_arg, the_arg2=None, *args, the_kwarg, **kwargs):
def get_template_data(self, args, kwargs, slots, context):
return {
"the_arg": the_arg,
"the_arg2": the_arg2,
"the_kwarg": the_kwarg,
"args": args,
"the_arg": args[0],
"the_arg2": args[1],
"the_kwarg": kwargs.pop("the_kwarg", None),
"args": args[2:],
"kwargs": kwargs,
}
@ -476,7 +501,7 @@ class TestComponentRender:
"""
the_arg: one
the_arg2: two
args: ('three',)
args: ['three']
the_kwarg: test
kwargs: {'kw2': 'ooo'}
---
@ -509,12 +534,12 @@ class TestComponentRender:
{% endslot %}
"""
def get_context_data(self, the_arg, the_arg2=None, *args, the_kwarg, **kwargs):
def get_template_data(self, args, kwargs, slots, context):
return {
"the_arg": the_arg,
"the_arg2": the_arg2,
"the_kwarg": the_kwarg,
"args": args,
"the_arg": args[0],
"the_arg2": args[1],
"the_kwarg": kwargs.pop("the_kwarg"),
"args": args[2:],
"kwargs": kwargs,
}
@ -531,7 +556,7 @@ class TestComponentRender:
"""
the_arg: one
the_arg2: two
args: ('three',)
args: ['three']
the_kwarg: test
kwargs: {'kw2': 'ooo'}
---
@ -580,10 +605,10 @@ class TestComponentRender:
{% endslot %}
"""
def get_context_data(self, the_arg, the_kwarg=None, **kwargs):
def get_template_data(self, args, kwargs, slots, context):
return {
"the_arg": the_arg,
"the_kwarg": the_kwarg,
"the_arg": args[0],
"the_kwarg": kwargs.pop("the_kwarg", None),
"kwargs": kwargs,
}
@ -592,7 +617,7 @@ class TestComponentRender:
# NOTE: Since the slot has access to the Context object, it should behave
# the same way as it does in templates - when in "isolated" mode, then the
# slot fill has access only to the "root" context, but not to the data of
# get_context_data() of SimpleComponent.
# get_template_data() of SimpleComponent.
if is_isolated:
assert ctx.get("the_arg") is None
assert ctx.get("the_kwarg") is None
@ -725,8 +750,8 @@ class TestComponentRender:
</div>
"""
def get_context_data(self, *args, how: str, **kwargs):
return {"how": how}
def get_template_data(self, args, kwargs, slots, context):
return {"how": kwargs.pop("how")}
class View(ComponentView):
def get(self, request):
@ -734,7 +759,7 @@ class TestComponentRender:
return self.component.render_to_response(
context=RequestContext(self.request),
kwargs=self.component.get_context_data(how=how),
kwargs={"how": how},
)
client = CustomClient(urlpatterns=[path("test_thing/", Thing.as_view())])
@ -869,7 +894,7 @@ class TestComponentRender:
class TestComponent(Component):
template = "Variable: <strong>{{ id }}</strong>"
def get_context_data(self, **attrs):
def get_template_data(self, args, kwargs, slots, context):
return {
"id": self.id,
}
@ -885,7 +910,7 @@ class TestComponentRender:
class TestComponent(Component):
template = "Variable: <strong>{{ id }}</strong>"
def get_context_data(self, **attrs):
def get_template_data(self, args, kwargs, slots, context):
return {
"id": self.id,
}
@ -923,7 +948,7 @@ class TestComponentHook:
{% endcomponent %}
"""
def get_context_data(self, *args, **kwargs):
def get_template_data(self, args, kwargs, slots, context):
return {
"args": args,
"kwargs": kwargs,
@ -943,7 +968,7 @@ class TestComponentHook:
assertHTMLEqual(
rendered,
"""
args: ()
args: []
kwargs: {}
---
from_on_before: :)
@ -984,7 +1009,7 @@ class TestComponentHook:
{% endcomponent %}
"""
def get_context_data(self, *args, **kwargs):
def get_template_data(self, args, kwargs, slots, context):
return {
"args": args,
"kwargs": kwargs,
@ -1006,7 +1031,7 @@ class TestComponentHook:
assertHTMLEqual(
captured_content,
"""
args: ()
args: []
kwargs: {}
---
from_on_after:
@ -1020,7 +1045,7 @@ class TestComponentHook:
assertHTMLEqual(
rendered,
"""
args: ()
args: []
kwargs: {}
---
from_on_after:
@ -1060,7 +1085,7 @@ class TestComponentHook:
{% endcomponent %}
"""
def get_context_data(self, *args, **kwargs):
def get_template_data(self, args, kwargs, slots, context):
return {
"args": args,
"kwargs": kwargs,
@ -1077,7 +1102,7 @@ class TestComponentHook:
assertHTMLEqual(
captured_content,
"""
args: ()
args: []
kwargs: {}
---
from_on_before:
@ -1092,7 +1117,7 @@ class TestComponentHook:
rendered,
"""
Chocolate cookie recipe:
args: ()
args: []
kwargs: {}
---
from_on_before:
@ -1131,7 +1156,7 @@ class TestComponentHook:
{% endcomponent %}
"""
def get_context_data(self, *args, **kwargs):
def get_template_data(self, args, kwargs, slots, context):
return {
"args": args,
"kwargs": kwargs,

View file

@ -1,5 +1,4 @@
import time
from typing import Any
from django.core.cache import caches
from django.template import Template
@ -33,7 +32,7 @@ class TestComponentCache:
class Cache:
enabled = True
def get_context_data(self, **kwargs: Any):
def get_template_data(self, args, kwargs, slots, context):
nonlocal did_call_get
did_call_get = True
return {}
@ -55,7 +54,7 @@ class TestComponentCache:
did_call_get = False
component.render()
# get_context_data not called because the cache entry was returned
# get_template_data not called because the cache entry was returned
assert not did_call_get
assert result == "Hello"
@ -68,7 +67,7 @@ class TestComponentCache:
class Cache:
enabled = False
def get_context_data(self, **kwargs: Any):
def get_template_data(self, args, kwargs, slots, context):
nonlocal did_call_get
did_call_get = True
return {}
@ -89,7 +88,7 @@ class TestComponentCache:
did_call_get = False
result = component.render()
# get_context_data IS called because the cache is NOT used
# get_template_data IS called because the cache is NOT used
assert did_call_get
assert result == "Hello"
@ -151,8 +150,8 @@ class TestComponentCache:
class Cache:
enabled = True
def get_context_data(self, input, **kwargs: Any):
return {"input": input}
def get_template_data(self, args, kwargs, slots, context):
return {"input": kwargs["input"]}
component = TestComponent()
component.render(
@ -200,7 +199,7 @@ class TestComponentCache:
# Custom hash method for args and kwargs
return "custom-args-and-kwargs"
def get_context_data(self, *args, **kwargs: Any):
def get_template_data(self, args, kwargs, slots, context):
return {}
component = TestComponent()

View file

@ -1,5 +1,4 @@
from dataclasses import field
from typing import Any
from django.template import Context
@ -25,25 +24,36 @@ class TestComponentDefaults:
extra = "extra"
fn = lambda: "fn_as_val" # noqa: E731
def get_context_data(self, arg1: Any, variable: Any, another: Any, **attrs: Any):
def get_template_data(self, args, kwargs, slots, context):
nonlocal did_call_context
did_call_context = True
# Check that args and slots are NOT affected by the defaults
assert self.input.args == [123]
assert [*self.input.slots.keys()] == ["my_slot"]
assert self.input.slots["my_slot"](Context(), None, None) == "MY_SLOT" # type: ignore[arg-type]
assert kwargs == {
"variable": "test", # User-given
"another": 1, # Default because missing
"extra": "extra", # Default because `None` was given
"fn": self.Defaults.fn, # Default because missing
}
assert self.input.kwargs == {
"variable": "test", # User-given
"another": 1, # Default because missing
"extra": "extra", # Default because `None` was given
"fn": self.Defaults.fn, # Default because missing
}
# Check that args and slots are NOT affected by the defaults
assert args == [123]
assert [*slots.keys()] == ["my_slot"]
assert slots["my_slot"](Context(), None, None) == "MY_SLOT" # type: ignore[arg-type]
assert self.input.args == [123]
assert [*self.input.slots.keys()] == ["my_slot"]
assert self.input.slots["my_slot"](Context(), None, None) == "MY_SLOT" # type: ignore[arg-type]
assert isinstance(self.input.context, Context)
return {
"variable": variable,
"variable": kwargs["variable"],
}
TestComponent.render(
@ -64,10 +74,14 @@ class TestComponentDefaults:
variable = "test"
fn = Default(lambda: "fn_as_factory")
def get_context_data(self, variable: Any, **attrs: Any):
def get_template_data(self, args, kwargs, slots, context):
nonlocal did_call_context
did_call_context = True
assert kwargs == {
"variable": "test", # User-given
"fn": "fn_as_factory", # Default because missing
}
assert self.input.kwargs == {
"variable": "test", # User-given
"fn": "fn_as_factory", # Default because missing
@ -75,7 +89,7 @@ class TestComponentDefaults:
assert isinstance(self.input.context, Context)
return {
"variable": variable,
"variable": kwargs["variable"],
}
TestComponent.render(
@ -94,10 +108,15 @@ class TestComponentDefaults:
variable = "test"
fn = field(default=lambda: "fn_as_factory")
def get_context_data(self, variable: Any, **attrs: Any):
def get_template_data(self, args, kwargs, slots, context):
nonlocal did_call_context
did_call_context = True
assert kwargs == {
"variable": "test", # User-given
# NOTE: NOT a factory, because it was set as `field(default=...)`
"fn": self.Defaults.fn.default, # type: ignore[attr-defined]
}
assert self.input.kwargs == {
"variable": "test", # User-given
# NOTE: NOT a factory, because it was set as `field(default=...)`
@ -106,7 +125,7 @@ class TestComponentDefaults:
assert isinstance(self.input.context, Context)
return {
"variable": variable,
"variable": kwargs["variable"],
}
TestComponent.render(
@ -125,10 +144,15 @@ class TestComponentDefaults:
variable = "test"
fn = field(default_factory=lambda: "fn_as_factory")
def get_context_data(self, variable: Any, **attrs: Any):
def get_template_data(self, args, kwargs, slots, context):
nonlocal did_call_context
did_call_context = True
assert kwargs == {
"variable": "test", # User-given
# NOTE: IS a factory, because it was set as `field(default_factory=...)`
"fn": "fn_as_factory", # Default because missing
}
assert self.input.kwargs == {
"variable": "test", # User-given
# NOTE: IS a factory, because it was set as `field(default_factory=...)`
@ -137,7 +161,7 @@ class TestComponentDefaults:
assert isinstance(self.input.context, Context)
return {
"variable": variable,
"variable": kwargs["variable"],
}
TestComponent.render(

View file

@ -132,9 +132,9 @@ class TestMainMedia:
css_file = "style.css"
js_file = "script.js"
def get_context_data(self, variable):
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": variable,
"variable": kwargs["variable"],
}
registry.register("test", TestComponent)
@ -231,10 +231,10 @@ class TestMainMedia:
Var2 (uppercased): <strong>{{ var2|upper }}</strong>
"""
def get_context_data(self, var1=None, var2=None):
def get_template_data(self, args, kwargs, slots, context):
return {
"var1": var1,
"var2": var2,
"var1": kwargs["var1"],
"var2": kwargs["var2"],
}
rendered = FilteredComponent.render(kwargs={"var1": "test1", "var2": "test2"})
@ -871,7 +871,7 @@ class TestMediaRelativePath:
</div>
""" # noqa
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {"shadowing_variable": "NOT SHADOWED"}
class VariableDisplay(Component):
@ -881,12 +881,12 @@ class TestMediaRelativePath:
<h1>Uniquely named variable = {{ unique_variable }}</h1>
"""
def get_context_data(self, shadowing_variable=None, new_variable=None):
def get_template_data(self, args, kwargs, slots, context):
context = {}
if shadowing_variable is not None:
context["shadowing_variable"] = shadowing_variable
if new_variable is not None:
context["unique_variable"] = new_variable
if kwargs["shadowing_variable"] is not None:
context["shadowing_variable"] = kwargs["shadowing_variable"]
if kwargs["new_variable"] is not None:
context["unique_variable"] = kwargs["new_variable"]
return context
# Settings required for autodiscover to work

View file

@ -142,7 +142,7 @@ class TestComponentTyping:
css_data_instance = None
class Button(Component):
# Data returned from `get_context_data`
# Data returned from `get_template_data`
@dataclass
class TemplateData:
data1: str
@ -232,7 +232,7 @@ class TestComponentTyping:
css_data_instance = None
class Button(Component):
# Data returned from `get_context_data`
# Data returned from `get_template_data`
@dataclass
class TemplateData:
data1: str
@ -348,7 +348,7 @@ class TestComponentTyping:
# The generic specifies the data available to the slot function
footer: NotRequired[Slot[ButtonFooterSlotData]]
# Data returned from `get_context_data`
# Data returned from `get_template_data`
class TemplateData(NamedTuple):
data1: str
data2: int

View file

@ -1,4 +1,4 @@
from typing import Any, Dict
from typing import Any
import pytest
from django.conf import settings
@ -60,8 +60,8 @@ class TestComponentAsView(SimpleTestCase):
</form>
"""
def get_context_data(self, variable, *args, **kwargs) -> Dict[str, Any]:
return {"variable": variable}
def get_template_data(self, args, kwargs, slots, context):
return {"variable": kwargs["variable"]}
def render_template_view(request):
template = Template(
@ -90,8 +90,8 @@ class TestComponentAsView(SimpleTestCase):
</form>
"""
def get_context_data(self, variable):
return {"inner_var": variable}
def get_template_data(self, args, kwargs, slots, context):
return {"inner_var": kwargs["variable"]}
class View(ComponentView):
def get(self, request, *args, **kwargs) -> HttpResponse:
@ -115,8 +115,8 @@ class TestComponentAsView(SimpleTestCase):
</form>
"""
def get_context_data(self, variable):
return {"inner_var": variable}
def get_template_data(self, args, kwargs, slots, context):
return {"inner_var": kwargs["variable"]}
def get(self, request, *args, **kwargs) -> HttpResponse:
return self.render_to_response(kwargs={"variable": "GET"})
@ -139,8 +139,8 @@ class TestComponentAsView(SimpleTestCase):
</form>
"""
def get_context_data(self, variable):
return {"inner_var": variable}
def get_template_data(self, args, kwargs, slots, context):
return {"inner_var": kwargs["variable"]}
class View(ComponentView):
def post(self, request, *args, **kwargs) -> HttpResponse:
@ -165,8 +165,8 @@ class TestComponentAsView(SimpleTestCase):
</form>
"""
def get_context_data(self, variable):
return {"inner_var": variable}
def get_template_data(self, args, kwargs, slots, context):
return {"inner_var": kwargs["variable"]}
def post(self, request, *args, **kwargs) -> HttpResponse:
variable = request.POST.get("variable")
@ -188,8 +188,8 @@ class TestComponentAsView(SimpleTestCase):
</form>
"""
def get_context_data(self, variable):
return {"inner_var": variable}
def get_template_data(self, args, kwargs, slots, context):
return {"inner_var": kwargs["variable"]}
def get(self, request, *args, **kwargs) -> HttpResponse:
return self.render_to_response(kwargs={"variable": self.name})

View file

@ -24,8 +24,8 @@ class SimpleComponent(Component):
Variable: <strong>{{ variable }}</strong>
"""
def get_context_data(self, variable=None):
return {"variable": variable} if variable is not None else {}
def get_template_data(self, args, kwargs, slots, context):
return {"variable": kwargs.get("variable", None)} if "variable" in kwargs else {}
class VariableDisplay(Component):
@ -35,12 +35,12 @@ class VariableDisplay(Component):
<h1>Uniquely named variable = {{ unique_variable }}</h1>
"""
def get_context_data(self, shadowing_variable=None, new_variable=None):
def get_template_data(self, args, kwargs, slots, context):
context = {}
if shadowing_variable is not None:
context["shadowing_variable"] = shadowing_variable
if new_variable is not None:
context["unique_variable"] = new_variable
if kwargs["shadowing_variable"] is not None:
context["shadowing_variable"] = kwargs["shadowing_variable"]
if kwargs["new_variable"] is not None:
context["unique_variable"] = kwargs["new_variable"]
return context
@ -55,8 +55,8 @@ class IncrementerComponent(Component):
super().__init__(*args, **kwargs)
self.call_count = 0
def get_context_data(self, value=0):
value = int(value)
def get_template_data(self, args, kwargs, slots, context):
value = int(kwargs.get("value", 0))
if hasattr(self, "call_count"):
self.call_count += 1
else:
@ -88,7 +88,7 @@ class TestContext:
</div>
""" # noqa
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {"shadowing_variable": "NOT SHADOWED"}
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
@ -231,8 +231,8 @@ class TestParentArgs:
</div>
""" # noqa
def get_context_data(self, parent_value):
return {"inner_parent_value": parent_value}
def get_template_data(self, args, kwargs, slots, context):
return {"inner_parent_value": kwargs["parent_value"]}
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_parent_args_can_be_drawn_from_context(self, components_settings):
@ -463,7 +463,7 @@ class TestIsolatedContext:
registry.register(name="simple_component", component=SimpleComponent)
template_str: types.django_html = """
{% load component_tags %}
{% component 'simple_component' variable only %}{% endcomponent %}
{% component 'simple_component' variable=variable only %}{% endcomponent %}
"""
template = Template(template_str)
rendered = template.render(Context({"variable": "outer_value"})).strip()
@ -490,7 +490,7 @@ class TestIsolatedContextSetting:
registry.register(name="simple_component", component=SimpleComponent)
template_str: types.django_html = """
{% load component_tags %}
{% component 'simple_component' variable %}{% endcomponent %}
{% component 'simple_component' variable=variable %}{% endcomponent %}
"""
template = Template(template_str)
rendered = template.render(Context({"variable": "outer_value"}))
@ -516,7 +516,7 @@ class TestIsolatedContextSetting:
registry.register(name="simple_component", component=SimpleComponent)
template_str: types.django_html = """
{% load component_tags %}
{% component 'simple_component' variable %}
{% component 'simple_component' variable=variable %}
{% endcomponent %}
"""
template = Template(template_str)
@ -549,7 +549,7 @@ class TestContextProcessors:
class TestComponent(Component):
template: types.django_html = """{% csrf_token %}"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
nonlocal context_processors_data
nonlocal inner_request
context_processors_data = self.context_processors_data
@ -585,7 +585,7 @@ class TestContextProcessors:
{% component "test_child" / %}
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
nonlocal context_processors_data
nonlocal parent_request
context_processors_data = self.context_processors_data
@ -596,7 +596,7 @@ class TestContextProcessors:
class TestChildComponent(Component):
template: types.django_html = """{% csrf_token %}"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
nonlocal context_processors_data_child
nonlocal child_request
context_processors_data_child = self.context_processors_data
@ -635,7 +635,7 @@ class TestContextProcessors:
{% endcomponent %}
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
nonlocal context_processors_data
nonlocal parent_request
context_processors_data = self.context_processors_data
@ -646,7 +646,7 @@ class TestContextProcessors:
class TestChildComponent(Component):
template: types.django_html = """{% csrf_token %}"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
nonlocal context_processors_data_child
nonlocal child_request
context_processors_data_child = self.context_processors_data
@ -680,7 +680,7 @@ class TestContextProcessors:
class TestComponent(Component):
template: types.django_html = """{% csrf_token %}"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
nonlocal context_processors_data
nonlocal inner_request
context_processors_data = self.context_processors_data
@ -709,7 +709,7 @@ class TestContextProcessors:
{% component "test_child" / %}
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
nonlocal context_processors_data
nonlocal parent_request
context_processors_data = self.context_processors_data
@ -720,7 +720,7 @@ class TestContextProcessors:
class TestChildComponent(Component):
template: types.django_html = """{% csrf_token %}"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
nonlocal context_processors_data_child
nonlocal child_request
context_processors_data_child = self.context_processors_data
@ -746,7 +746,7 @@ class TestContextProcessors:
class TestComponent(Component):
template: types.django_html = """{% csrf_token %}"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
nonlocal context_processors_data
nonlocal inner_request
context_processors_data = self.context_processors_data
@ -774,7 +774,7 @@ class TestContextProcessors:
{% component "test_child" / %}
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
nonlocal context_processors_data
nonlocal parent_request
context_processors_data = self.context_processors_data
@ -785,7 +785,7 @@ class TestContextProcessors:
class TestChildComponent(Component):
template: types.django_html = """{% csrf_token %}"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
nonlocal context_processors_data_child
nonlocal child_request
context_processors_data_child = self.context_processors_data
@ -811,7 +811,7 @@ class TestContextProcessors:
class TestComponent(Component):
template: types.django_html = """{% csrf_token %}"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
nonlocal context_processors_data
nonlocal inner_request
context_processors_data = self.context_processors_data
@ -834,7 +834,7 @@ class TestContextProcessors:
class TestComponent(Component):
template: types.django_html = """{% csrf_token %}"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
nonlocal context_processors_data
nonlocal inner_request
context_processors_data = self.context_processors_data
@ -857,7 +857,7 @@ class TestContextProcessors:
class TestComponent(Component):
template: types.django_html = """{% csrf_token %}"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
nonlocal context_processors_data
nonlocal inner_request
context_processors_data = self.context_processors_data
@ -902,7 +902,7 @@ class TestOuterContextProperty:
Variable: <strong>{{ variable }}</strong>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return self.outer_context.flatten() # type: ignore[union-attr]
template_str: types.django_html = """

View file

@ -38,10 +38,10 @@ class SimpleComponent(Component):
console.log("xyz");
"""
def get_context_data(self, variable, variable2="default"):
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": variable,
"variable2": variable2,
"variable": kwargs["variable"],
"variable2": kwargs.get("variable2", "default"),
}
class Media:
@ -551,7 +551,7 @@ class TestDependenciesStrategySimple:
console.log("Hello");
"""
def get_context_data(self, variable):
def get_template_data(self, args, kwargs, slots, context):
return {}
class Media:
@ -573,7 +573,7 @@ class TestDependenciesStrategySimple:
console.log("xyz");
"""
def get_context_data(self, variable):
def get_template_data(self, args, kwargs, slots, context):
return {}
class Media:
@ -711,7 +711,7 @@ class TestDependenciesStrategyPrepend:
console.log("Hello");
"""
def get_context_data(self, variable):
def get_template_data(self, args, kwargs, slots, context):
return {}
class Media:
@ -733,7 +733,7 @@ class TestDependenciesStrategyPrepend:
console.log("xyz");
"""
def get_context_data(self, variable):
def get_template_data(self, args, kwargs, slots, context):
return {}
class Media:
@ -868,7 +868,7 @@ class TestDependenciesStrategyAppend:
console.log("Hello");
"""
def get_context_data(self, variable):
def get_template_data(self, args, kwargs, slots, context):
return {}
class Media:
@ -890,7 +890,7 @@ class TestDependenciesStrategyAppend:
console.log("xyz");
"""
def get_context_data(self, variable):
def get_template_data(self, args, kwargs, slots, context):
return {}
class Media:

View file

@ -25,10 +25,10 @@ class SimpleComponent(Component):
Variable: <strong>{{ variable }}</strong>
"""
def get_context_data(self, variable, variable2="default"):
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": variable,
"variable2": variable2,
"variable": kwargs["variable"],
"variable2": kwargs.get("variable2", "default"),
}
class Media:
@ -55,7 +55,7 @@ class SimpleComponentNested(Component):
console.log("Hello");
"""
def get_context_data(self, variable):
def get_template_data(self, args, kwargs, slots, context):
return {}
class Media:
@ -78,7 +78,7 @@ class OtherComponent(Component):
console.log("xyz");
"""
def get_context_data(self, variable):
def get_template_data(self, args, kwargs, slots, context):
return {}
class Media:
@ -91,7 +91,7 @@ class SimpleComponentWithSharedDependency(Component):
Variable: <strong>{{ variable }}</strong>
"""
def get_context_data(self, variable, variable2="default"):
def get_template_data(self, args, kwargs, slots, context):
return {}
class Media:

View file

@ -1,7 +1,7 @@
"""Catch-all for tests that use template tags and don't fit other files"""
import re
from typing import Any, Dict
from typing import Dict
import pytest
from django.template import Context, Template, TemplateSyntaxError
@ -68,21 +68,15 @@ class TestDynamicExpr:
@register("test")
class SimpleComponent(Component):
def get_context_data(
self,
pos_var1: Any,
*args: Any,
bool_var: bool,
list_var: Dict,
):
captured["pos_var1"] = pos_var1
captured["bool_var"] = bool_var
captured["list_var"] = list_var
def get_template_data(self, args, kwargs, slots, context):
captured["pos_var1"] = args[0]
captured["bool_var"] = kwargs["bool_var"]
captured["list_var"] = kwargs["list_var"]
return {
"pos_var1": pos_var1,
"bool_var": bool_var,
"list_var": list_var,
"pos_var1": args[0],
"bool_var": kwargs["bool_var"],
"list_var": kwargs["list_var"],
}
template: types.django_html = """
@ -135,24 +129,17 @@ class TestDynamicExpr:
@register("test")
class SimpleComponent(Component):
def get_context_data(
self,
pos_var1: Any,
*args: Any,
bool_var: bool,
list_var: Dict,
dict_var: Dict,
):
captured["pos_var1"] = pos_var1
captured["bool_var"] = bool_var
captured["list_var"] = list_var
captured["dict_var"] = dict_var
def get_template_data(self, args, kwargs, slots, context):
captured["pos_var1"] = args[0]
captured["bool_var"] = kwargs["bool_var"]
captured["list_var"] = kwargs["list_var"]
captured["dict_var"] = kwargs["dict_var"]
return {
"pos_var1": pos_var1,
"bool_var": bool_var,
"list_var": list_var,
"dict_var": dict_var,
"pos_var1": args[0],
"bool_var": kwargs["bool_var"],
"list_var": kwargs["list_var"],
"dict_var": kwargs["dict_var"],
}
template: types.django_html = """
@ -209,24 +196,17 @@ class TestDynamicExpr:
@register("test")
class SimpleComponent(Component):
def get_context_data(
self,
pos_var1: Any,
pos_var2: Any,
*args: Any,
bool_var: bool,
list_var: Dict,
):
captured["pos_var1"] = pos_var1
captured["pos_var2"] = pos_var2
captured["bool_var"] = bool_var
captured["list_var"] = list_var
def get_template_data(self, args, kwargs, slots, context):
captured["pos_var1"] = args[0]
captured["pos_var2"] = args[1]
captured["bool_var"] = kwargs["bool_var"]
captured["list_var"] = kwargs["list_var"]
return {
"pos_var1": pos_var1,
"pos_var2": pos_var2,
"bool_var": bool_var,
"list_var": list_var,
"pos_var1": args[0],
"pos_var2": args[1],
"bool_var": kwargs["bool_var"],
"list_var": kwargs["list_var"],
}
template: types.django_html = """
@ -281,26 +261,18 @@ class TestDynamicExpr:
@register("test")
class SimpleComponent(Component):
def get_context_data(
self,
pos_var1: Any,
pos_var2: Any,
*args: Any,
bool_var: bool,
list_var: Dict,
dict_var: Dict,
):
captured["pos_var1"] = pos_var1
captured["bool_var"] = bool_var
captured["list_var"] = list_var
captured["dict_var"] = dict_var
def get_template_data(self, args, kwargs, slots, context):
captured["pos_var1"] = args[0]
captured["bool_var"] = kwargs["bool_var"]
captured["list_var"] = kwargs["list_var"]
captured["dict_var"] = kwargs["dict_var"]
return {
"pos_var1": pos_var1,
"pos_var2": pos_var2,
"bool_var": bool_var,
"list_var": list_var,
"dict_var": dict_var,
"pos_var1": args[0],
"pos_var2": args[1],
"bool_var": kwargs["bool_var"],
"list_var": kwargs["list_var"],
"dict_var": kwargs["dict_var"],
}
template: types.django_html = """
@ -357,17 +329,11 @@ class TestDynamicExpr:
@register("test")
class SimpleComponent(Component):
def get_context_data(
self,
pos_var1: Any,
pos_var2: Any,
*args: Any,
bool_var: bool,
):
def get_template_data(self, args, kwargs, slots, context):
return {
"pos_var1": pos_var1,
"pos_var2": pos_var2,
"bool_var": bool_var,
"pos_var1": args[0],
"pos_var2": args[1],
"bool_var": kwargs["bool_var"],
}
template: types.django_html = """
@ -404,15 +370,10 @@ class TestDynamicExpr:
@register("test")
class SimpleComponent(Component):
def get_context_data(
self,
pos_var1: Any,
*args: Any,
bool_var: bool,
):
def get_template_data(self, args, kwargs, slots, context):
return {
"pos_var1": pos_var1,
"bool_var": bool_var,
"pos_var1": args[0],
"bool_var": kwargs["bool_var"],
}
template: types.django_html = """
@ -461,17 +422,12 @@ class TestSpreadOperator:
@register("test")
class SimpleComponent(Component):
def get_context_data(
self,
pos_var1: Any,
*args: Any,
**kwargs: Any,
):
def get_template_data(self, args, kwargs, slots, context):
nonlocal captured
captured = kwargs
return {
"pos_var1": pos_var1,
"pos_var1": args[0],
**kwargs,
}
@ -531,7 +487,7 @@ class TestSpreadOperator:
def test_slot(self, components_settings):
@register("test")
class SimpleComponent(Component):
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"my_dict": {
"attrs:@click": "() => {}",
@ -568,7 +524,7 @@ class TestSpreadOperator:
def test_fill(self, components_settings):
@register("test")
class SimpleComponent(Component):
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"my_dict": {
"attrs:@click": "() => {}",
@ -618,7 +574,7 @@ class TestSpreadOperator:
def test_provide(self, components_settings):
@register("test")
class SimpleComponent(Component):
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
data = self.inject("test")
return {
"attrs": data.attrs,
@ -692,11 +648,7 @@ class TestSpreadOperator:
def test_later_spreads_do_not_overwrite_earlier(self, components_settings):
@register("test")
class SimpleComponent(Component):
def get_context_data(
self,
*args: Any,
**kwargs: Any,
):
def get_template_data(self, args, kwargs, slots, context):
return {
**kwargs,
}
@ -794,7 +746,7 @@ class TestSpreadOperator:
class SimpleComponent(Component):
template = ""
def get_context_data(self, *args, **kwargs):
def get_template_data(self, args, kwargs, slots, context):
nonlocal captured
captured = args, kwargs
return {}
@ -820,7 +772,7 @@ class TestSpreadOperator:
template.render(context)
assert captured == (
("a", "b", "c", 1, 2, 3),
["a", "b", "c", 1, 2, 3],
{},
)
@ -858,7 +810,7 @@ class TestAggregateKwargs:
class Test(Component):
template = ""
def get_context_data(self, *args, **kwargs):
def get_template_data(self, args, kwargs, slots, context):
nonlocal captured
captured = args, kwargs
return {}
@ -879,7 +831,7 @@ class TestAggregateKwargs:
template.render(Context({"class_var": "padding-top-8", "four": 4}))
assert captured == (
(),
[],
{
"attrs": {
"@click.stop": "dispatch('click_event')",

View file

@ -116,8 +116,8 @@ def with_component_cls(on_created: Callable):
class TempComponent(Component):
template = "Hello {{ name }}!"
def get_context_data(self, name="World"):
return {"name": name}
def get_template_data(self, args, kwargs, slots, context):
return {"name": kwargs.get("name", "World")}
on_created()
@ -143,8 +143,8 @@ class TestExtension:
class TestAccessComp(Component):
template = "Hello {{ name }}!"
def get_context_data(self, arg1, arg2, name="World"):
return {"name": name}
def get_template_data(self, args, kwargs, slots, context):
return {"name": kwargs.get("name", "World")}
ext_class = TestAccessComp.TestExtension # type: ignore[attr-defined]
assert issubclass(ext_class, ComponentExtension.ExtensionClass)
@ -240,8 +240,8 @@ class TestExtensionHooks:
class TestComponent(Component):
template = "Hello {{ name }}!"
def get_context_data(self, name="World"):
return {"name": name}
def get_template_data(self, args, kwargs, slots, context):
return {"name": kwargs.get("name", "World")}
registry.register("test_comp", TestComponent)
extension = cast(DummyExtension, app_settings.EXTENSIONS[3])
@ -268,13 +268,13 @@ class TestExtensionHooks:
class TestComponent(Component):
template = "Hello {{ name }}!"
def get_context_data(self, arg1, arg2, name="World"):
return {"name": name}
def get_template_data(self, args, kwargs, slots, context):
return {"name": kwargs.get("name", "World")}
def get_js_data(self, *args, **kwargs):
def get_js_data(self, args, kwargs, slots, context):
return {"script": "console.log('Hello!')"}
def get_css_data(self, *args, **kwargs):
def get_css_data(self, args, kwargs, slots, context):
return {"style": "body { color: blue; }"}
# Render the component with some args and kwargs

View file

@ -182,9 +182,9 @@ class TestMultipleComponentRegistries:
Slot: {% slot "default" default / %}
"""
def get_context_data(self, variable=None):
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": variable,
"variable": kwargs.get("variable", None),
}
registry_a.register("simple_a", SimpleComponent)

View file

@ -51,10 +51,10 @@ class TestTemplateSignal:
class InnerComponent(Component):
template_file = "simple_template.html"
def get_context_data(self, variable, variable2="default"):
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": variable,
"variable2": variable2,
"variable": kwargs["variable"],
"variable2": kwargs.get("variable2", "default"),
}
class Media:

View file

@ -2706,7 +2706,7 @@ class TestResolver:
@register("test")
class Test(Component):
def get_context_data(self, **kwargs):
def get_template_data(self, args, kwargs, slots, context):
nonlocal captured
captured = kwargs
return {}
@ -2771,7 +2771,7 @@ class TestResolver:
class Test(Component):
template = "var"
def get_context_data(self, *args, **kwargs):
def get_template_data(self, args, kwargs, slots, context):
nonlocal captured
captured = args, kwargs
return {}
@ -2783,7 +2783,7 @@ class TestResolver:
"""
Template(template_str).render(Context({"myvar": "myval", "val2": [1, 2, 3]}))
assert captured == ((42, "myval"), {"key": "val", "key2": [1, 2, 3]})
assert captured == ([42, "myval"], {"key": "val", "key2": [1, 2, 3]})
def test_component_special_kwargs(self):
captured = None
@ -2792,7 +2792,7 @@ class TestResolver:
class Test(Component):
template = "var"
def get_context_data(self, *args, **kwargs):
def get_template_data(self, args, kwargs, slots, context):
nonlocal captured
captured = args, kwargs
return {}
@ -2805,7 +2805,7 @@ class TestResolver:
Template(template_str).render(Context({"date": 2024, "bzz": "fzz"}))
assert captured == (
tuple([]),
[],
{
"date": 2024,
"@lol": 2,

View file

@ -33,9 +33,9 @@ class TestTemplateCache:
"""
return content
def get_context_data(self, variable=None):
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": variable,
"variable": kwargs.get("variable", None),
}
comp = SimpleComponent()

View file

@ -215,8 +215,8 @@ class TestTemplateParser:
Slot: {% slot "content" default / %}
"""
def get_context_data(self, var: str) -> dict:
return {"var": var}
def get_template_data(self, args, kwargs, slots, context):
return {"var": kwargs["var"]}
template_str: types.django_html = """
{% load component_tags %}

View file

@ -29,17 +29,17 @@ class TestMultilineTags:
Variable: <strong>{{ variable }}</strong>
"""
def get_context_data(self, variable, variable2="default"):
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": variable,
"variable2": variable2,
"variable": kwargs["variable"],
"variable2": kwargs.get("variable2", "default"),
}
template: types.django_html = """
{% load component_tags %}
{% component
"test_component"
123
variable=123
variable2="abc"
%}
{% endcomponent %}
@ -58,9 +58,9 @@ class TestNestedTags:
Variable: <strong>{{ var }}</strong>
"""
def get_context_data(self, var):
def get_template_data(self, args, kwargs, slots, context):
return {
"var": var,
"var": kwargs["var"],
}
# See https://github.com/django-components/django-components/discussions/671

View file

@ -1,4 +1,5 @@
import re
from typing import NamedTuple
import pytest
from django.template import Context, Template, TemplateSyntaxError
@ -25,8 +26,8 @@ class SlottedComponentWithContext(Component):
</custom-template>
"""
def get_context_data(self, variable):
return {"variable": variable}
def get_template_data(self, args, kwargs, slots, context):
return {"variable": kwargs["variable"]}
#######################
@ -41,10 +42,10 @@ class TestComponentTemplateTag:
Variable: <strong>{{ variable }}</strong>
"""
def get_context_data(self, variable, variable2="default"):
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": variable,
"variable2": variable2,
"variable": kwargs["variable"],
"variable2": kwargs.get("variable2", "default"),
}
class Media:
@ -114,10 +115,10 @@ class TestComponentTemplateTag:
{% endif %}
"""
def get_context_data(self, variable, variable2="default"):
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": variable,
"variable2": variable2,
"variable": kwargs["variable"],
"variable2": kwargs.get("variable2", "default"),
}
class Media:
@ -178,8 +179,11 @@ class TestComponentTemplateTag:
Default: <p>{{ default_param }}</p>
"""
def get_context_data(self, variable, default_param="default text"):
return {"variable": variable, "default_param": default_param}
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": kwargs["variable"],
"default_param": kwargs.get("default_param", "default text"),
}
template_str: types.django_html = """
{% load component_tags %}
@ -204,10 +208,17 @@ class TestDynamicComponentTemplateTag:
Variable: <strong>{{ variable }}</strong>
"""
def get_context_data(self, variable, variable2="default"):
class Kwargs(NamedTuple):
variable: str
variable2: str
class Defaults:
variable2 = "default"
def get_template_data(self, args, kwargs: Kwargs, slots, context):
return {
"variable": variable,
"variable2": variable2,
"variable": kwargs.variable,
"variable2": kwargs.variable2,
}
class Media:
@ -375,10 +386,10 @@ class TestDynamicComponentTemplateTag:
Slot: {% slot "default" default / %}
"""
def get_context_data(self, variable, variable2="default"):
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": variable,
"variable2": variable2,
"variable": kwargs["variable"],
"variable2": kwargs.get("variable2", "default"),
}
registry.register(name="test", component=SimpleSlottedComponent)
@ -412,10 +423,10 @@ class TestDynamicComponentTemplateTag:
Slot 2: {% slot "two" / %}
"""
def get_context_data(self, variable, variable2="default"):
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": variable,
"variable2": variable2,
"variable": kwargs["variable"],
"variable2": kwargs.get("variable2", "default"),
}
registry.register(name="test", component=SimpleSlottedComponent)
@ -455,10 +466,10 @@ class TestDynamicComponentTemplateTag:
Slot 2: {% slot "two" / %}
"""
def get_context_data(self, variable, variable2="default"):
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": variable,
"variable2": variable2,
"variable": kwargs["variable"],
"variable2": kwargs.get("variable2", "default"),
}
registry.register(name="test", component=SimpleSlottedComponent)
@ -722,8 +733,11 @@ class TestAggregateInput:
</div>
"""
def get_context_data(self, *args, attrs, my_dict):
return {"attrs": attrs, "my_dict": my_dict}
def get_template_data(self, args, kwargs, slots, context):
return {
"attrs": kwargs["attrs"],
"my_dict": kwargs["my_dict"],
}
template_str: types.django_html = """
{% load component_tags %}
@ -751,9 +765,12 @@ class TestRecursiveComponent:
@register("recursive")
class Recursive(Component):
def get_context_data(self, depth: int = 0):
print("depth:", depth)
return {"depth": depth + 1, "DEPTH": DEPTH}
class Defaults:
depth = 0
def get_template_data(self, args, kwargs, slots, context):
print("depth:", kwargs["depth"])
return {"depth": kwargs["depth"] + 1, "DEPTH": DEPTH}
template: types.django_html = """
<div>

View file

@ -820,7 +820,7 @@ class TestExtendsCompat:
<div> injected: {{ var|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
var = self.inject("block_provide")
return {"var": var}

View file

@ -1,5 +1,4 @@
import re
from typing import Any
import pytest
from django.template import Context, Template, TemplateSyntaxError
@ -29,7 +28,7 @@ class TestProvideTemplateTag:
<div> injected: {{ var|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
var = self.inject("my_provide", "default")
return {"var": var}
@ -79,7 +78,7 @@ class TestProvideTemplateTag:
<div> another: {{ another }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
my_provide = self.inject("my_provide")
return {
"key": my_provide.key,
@ -114,7 +113,7 @@ class TestProvideTemplateTag:
<div> another: {{ my_provide.another }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
my_provide = self.inject("my_provide")
return {
"my_provide": my_provide,
@ -147,7 +146,7 @@ class TestProvideTemplateTag:
<div> injected: {{ var|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
var = self.inject("my_provide", "default")
return {"var": var}
@ -179,7 +178,7 @@ class TestProvideTemplateTag:
<div> injected: {{ var|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
var = self.inject("my_provide", "default")
return {"var": var}
@ -214,7 +213,7 @@ class TestProvideTemplateTag:
<div></div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {}
template_str: types.django_html = """
@ -246,7 +245,7 @@ class TestProvideTemplateTag:
<div> injected: {{ var|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
var = self.inject("my_provide", "default")
return {"var": var}
@ -279,7 +278,7 @@ class TestProvideTemplateTag:
<div> injected: {{ var|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
var = self.inject("my_provide", "default")
return {"var": var}
@ -318,7 +317,7 @@ class TestProvideTemplateTag:
<div> injected: {{ var|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
var = self.inject("my_provide", "default")
return {"var": var}
@ -361,7 +360,7 @@ class TestProvideTemplateTag:
<div> injected: {{ var|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
var = self.inject("my_provide", "default")
return {"var": var}
@ -390,7 +389,7 @@ class TestProvideTemplateTag:
<div> injected: {{ var|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
var = self.inject("my_provide", "default")
return {"var": var}
@ -419,7 +418,7 @@ class TestProvideTemplateTag:
<div> injected: {{ var|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
var = self.inject("my_provide", "default")
return {"var": var}
@ -446,7 +445,7 @@ class TestProvideTemplateTag:
<div> injected: {{ var|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
var = self.inject("my_provide", "default")
return {"var": var}
@ -478,7 +477,7 @@ class TestProvideTemplateTag:
<div> injected: {{ var|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
var = self.inject("my_provide", "default")
return {"var": var}
@ -515,7 +514,7 @@ class TestProvideTemplateTag:
<div> injected: {{ var|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
var = self.inject("my_provide", "default")
return {"var": var}
@ -558,7 +557,7 @@ class TestProvideTemplateTag:
<div> second_provide: {{ second_provide|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
first_provide = self.inject("first_provide", "default")
second_provide = self.inject("second_provide", "default")
return {
@ -595,7 +594,7 @@ class TestProvideTemplateTag:
<div> injected: {{ var|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
var = self.inject("my_provide", "default")
return {"var": var}
@ -626,7 +625,7 @@ class TestProvideTemplateTag:
<div> injected: {{ var|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
var = self.inject("my_provide", "default")
return {"var": var}
@ -674,7 +673,7 @@ class TestInject:
<div> injected: {{ var|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
var = self.inject("my_provide")
return {"var": var}
@ -704,7 +703,7 @@ class TestInject:
<div> injected: {{ var|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
var = self.inject("abc")
return {"var": var}
@ -728,7 +727,7 @@ class TestInject:
<div> injected: {{ var|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
var = self.inject("abc", "default")
return {"var": var}
@ -755,7 +754,7 @@ class TestInject:
<div> injected: {{ var|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
var = self.inject("")
return {"var": var}
@ -783,7 +782,7 @@ class TestInject:
<div> injected: {{ var|safe }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
var = self.inject("abc", "default")
return {"var": var}
@ -806,14 +805,14 @@ class TestInject:
</main>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
data = self.inject("my_provide")
return {"data": data}
@register("provider")
class Provider(Component):
def get_context_data(self, data: Any) -> Any:
return {"data": data}
def get_template_data(self, args, kwargs, slots, context):
return {"data": kwargs["data"]}
template: types.django_html = """
{% load component_tags %}
@ -824,8 +823,8 @@ class TestInject:
@register("parent")
class Parent(Component):
def get_context_data(self, data: Any) -> Any:
return {"data": data}
def get_template_data(self, args, kwargs, slots, context):
return {"data": kwargs["data"]}
template: types.django_html = """
{% load component_tags %}
@ -875,14 +874,14 @@ class TestInject:
</main>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
data = self.inject("my_provide")
return {"data": data}
@register("provider")
class Provider(Component):
def get_context_data(self, data: Any) -> Any:
return {"data": data}
def get_template_data(self, args, kwargs, slots, context):
return {"data": kwargs["data"]}
template: types.django_html = """
{% load component_tags %}
@ -893,8 +892,8 @@ class TestInject:
@register("parent")
class Parent(Component):
def get_context_data(self, data: Any) -> Any:
return {"data": data}
def get_template_data(self, args, kwargs, slots, context):
return {"data": kwargs["data"]}
template: types.django_html = """
{% load component_tags %}
@ -949,7 +948,7 @@ class TestProvideCache:
<div> Ran: {{ ran }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
assert len(provide_cache) == 1
data = self.inject("my_provide")
@ -989,7 +988,7 @@ class TestProvideCache:
class Injectee(Component):
template = ""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
assert len(provide_cache) == 1
data = self.inject("my_provide")
@ -1022,7 +1021,7 @@ class TestProvideCache:
<div> Ran: {{ ran }} </div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
assert len(provide_cache) == 1
data = self.inject("my_provide")
@ -1059,7 +1058,7 @@ class TestProvideCache:
class Injectee(Component):
template = ""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
assert len(provide_cache) == 1
data = self.inject("my_provide")

View file

@ -1,5 +1,5 @@
import re
from typing import Any, Dict, List, Optional
from typing import Dict
import pytest
from django.template import Context, Template, TemplateSyntaxError
@ -40,10 +40,10 @@ class TestComponentSlot:
class SimpleComponent(Component):
template = """Variable: <strong>{{ variable }}</strong>"""
def get_context_data(self, variable, variable2="default"):
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": variable,
"variable2": variable2,
"variable": kwargs["variable"],
"variable2": kwargs.get("variable2", "default"),
}
class Media:
@ -96,10 +96,10 @@ class TestComponentSlot:
class SimpleComponent(Component):
template = """Variable: <strong>{{ variable }}</strong>"""
def get_context_data(self, variable, variable2="default"):
def get_template_data(self, args, kwargs, slots, context):
return {
"variable": variable,
"variable2": variable2,
"variable": kwargs["variable"],
"variable2": kwargs.get("variable2", "default"),
}
template_str: types.django_html = """
@ -152,8 +152,8 @@ class TestComponentSlot:
</custom-template>
"""
def get_context_data(self, variable):
return {"variable": variable}
def get_template_data(self, args, kwargs, slots, context):
return {"variable": kwargs["variable"]}
template_str: types.django_html = """
{% load component_tags %}
@ -294,9 +294,9 @@ class TestComponentSlot:
</div>
"""
def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]:
def get_template_data(self, args, kwargs, slots, context):
return {
"name": name,
"name": kwargs.get("name", None),
}
registry.register("test", SlottedComponent)
@ -451,8 +451,8 @@ class TestComponentSlot:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_multiple_slots_with_same_name_different_flags(self, components_settings):
class TestComp(Component):
def get_context_data(self, required: bool) -> Any:
return {"required": required}
def get_template_data(self, args, kwargs, slots, context):
return {"required": kwargs["required"]}
template: types.django_html = """
{% load component_tags %}
@ -824,8 +824,8 @@ class TestComponentSlotDefault:
def test_implicit_fill_when_slot_marked_default_not_rendered(self, components_settings):
@register("test_comp")
class ConditionalSlotted(Component):
def get_context_data(self, var: bool) -> Any:
return {"var": var}
def get_template_data(self, args, kwargs, slots, context):
return {"var": kwargs["var"]}
template: types.django_html = """
{% load component_tags %}
@ -885,9 +885,9 @@ class TestPassthroughSlots:
</custom-template>
"""
def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]:
def get_template_data(self, args, kwargs, slots, context):
return {
"name": name,
"name": kwargs.get("name", None),
}
template_str: types.django_html = """
@ -941,9 +941,9 @@ class TestPassthroughSlots:
</custom-template>
"""
def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]:
def get_template_data(self, args, kwargs, slots, context):
return {
"name": name,
"name": kwargs.get("name", None),
}
template_str: types.django_html = """
@ -985,9 +985,9 @@ class TestPassthroughSlots:
</custom-template>
"""
def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]:
def get_template_data(self, args, kwargs, slots, context):
return {
"name": name,
"name": kwargs.get("name", None),
}
template_str: types.django_html = """
@ -1021,7 +1021,7 @@ class TestPassthroughSlots:
def test_slots_inside_loops(self, components_settings):
@register("test_comp")
class OuterComp(Component):
def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]:
def get_template_data(self, args, kwargs, slots, context):
return {
"slots": ["header", "main", "footer"],
}
@ -1064,7 +1064,7 @@ class TestPassthroughSlots:
@register("test_comp")
class OuterComp(Component):
def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]:
def get_template_data(self, args, kwargs, slots, context):
return {
"slots": self.input.slots,
}
@ -1115,7 +1115,7 @@ class TestPassthroughSlots:
@register("test_comp")
class OuterComp(Component):
def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]:
def get_template_data(self, args, kwargs, slots, context):
return {
"slots": self.input.slots,
}
@ -1510,7 +1510,7 @@ class TestScopedSlot:
</div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"abc": "def",
"var123": 456,
@ -1545,7 +1545,7 @@ class TestScopedSlot:
</div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"abc": "def",
"var123": 456,
@ -1580,7 +1580,7 @@ class TestScopedSlot:
</div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"abc": "def",
"var123": 456,
@ -1617,7 +1617,7 @@ class TestScopedSlot:
</div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"slot_name": "my_slot",
"abc": "def",
@ -1653,7 +1653,7 @@ class TestScopedSlot:
</div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"slot_props": {
"name": "my_slot",
@ -1692,7 +1692,7 @@ class TestScopedSlot:
</div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"abc": "xyz",
"var123": 456,
@ -1728,7 +1728,7 @@ class TestScopedSlot:
</div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"abc": "def",
"var123": 456,
@ -1759,7 +1759,7 @@ class TestScopedSlot:
</div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"abc": "def",
"var123": 456,
@ -1811,7 +1811,7 @@ class TestScopedSlot:
</div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"abc": "def",
"var123": 456,
@ -1837,7 +1837,7 @@ class TestScopedSlot:
</div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"abc": "def",
"var123": 456,
@ -1880,7 +1880,7 @@ class TestScopedSlot:
</div>
"""
def get_context_data(self):
def get_template_data(self, args, kwargs, slots, context):
return {
"abc": "def",
"var123": 456,
@ -1925,10 +1925,10 @@ class TestScopedSlot:
</div>
"""
def get_context_data(self, input):
def get_template_data(self, args, kwargs, slots, context):
return {
"abc": "def",
"input": input,
"input": kwargs["input"],
}
template_str: types.django_html = """
@ -1974,9 +1974,9 @@ class TestDuplicateSlot:
<footer>{% slot "footer" %}Default footer{% endslot %}</footer>
"""
def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]:
def get_template_data(self, args, kwargs, slots, context):
return {
"name": name,
"name": kwargs.get("name", None),
}
return DuplicateSlotComponent
@ -2001,9 +2001,9 @@ class TestDuplicateSlot:
</div>
"""
def get_context_data(self, items: List) -> Dict[str, Any]:
def get_template_data(self, args, kwargs, slots, context):
return {
"items": items,
"items": kwargs["items"],
}
return DuplicateSlotNestedComponent
@ -2243,9 +2243,9 @@ class TestSlotBehavior:
</custom-template>
"""
def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]:
def get_template_data(self, args, kwargs, slots, context):
return {
"name": name,
"name": kwargs.get("name", None),
}
registry.register("test", SlottedComponent)
@ -2360,7 +2360,7 @@ class TestSlotBehavior:
class TestSlotInput:
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_slots_accessible_when_python_render(self, components_settings):
slots: Dict = {}
seen_slots: Dict = {}
@register("test")
class SlottedComponent(Component):
@ -2371,12 +2371,12 @@ class TestSlotInput:
<footer>{% slot "footer" %}Default footer{% endslot %}</footer>
"""
def get_context_data(self, input: Optional[int] = None) -> Dict[str, Any]:
nonlocal slots
slots = self.input.slots
def get_template_data(self, args, kwargs, slots, context):
nonlocal seen_slots
seen_slots = slots
return {}
assert slots == {}
assert seen_slots == {}
template_str: types.django_html = """
{% load component_tags %}
@ -2390,14 +2390,14 @@ class TestSlotInput:
template = Template(template_str)
template.render(Context())
assert list(slots.keys()) == ["header", "main"]
assert callable(slots["header"])
assert callable(slots["main"])
assert "footer" not in slots
assert list(seen_slots.keys()) == ["header", "main"]
assert callable(seen_slots["header"])
assert callable(seen_slots["main"])
assert "footer" not in seen_slots
@djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR)
def test_slots_normalized_as_slot_instances(self, components_settings):
slots: Dict[str, Slot] = {}
seen_slots: Dict[str, Slot] = {}
@register("test")
class SlottedComponent(Component):
@ -2408,12 +2408,12 @@ class TestSlotInput:
<footer>{% slot "footer" %}Default footer{% endslot %}</footer>
"""
def get_context_data(self, input: Optional[int] = None) -> Dict[str, Any]:
nonlocal slots
slots = self.input.slots
def get_template_data(self, args, kwargs, slots, context):
nonlocal seen_slots
seen_slots = slots
return {}
assert slots == {}
assert seen_slots == {}
header_slot = Slot(lambda *a, **kw: "HEADER_SLOT")
main_slot_str = "MAIN_SLOT"
@ -2427,11 +2427,11 @@ class TestSlotInput:
}
)
assert isinstance(slots["header"], Slot)
assert slots["header"](Context(), None, None) == "HEADER_SLOT" # type: ignore[arg-type]
assert isinstance(seen_slots["header"], Slot)
assert seen_slots["header"](Context(), None, None) == "HEADER_SLOT" # type: ignore[arg-type]
assert isinstance(slots["main"], Slot)
assert slots["main"](Context(), None, None) == "MAIN_SLOT" # type: ignore[arg-type]
assert isinstance(seen_slots["main"], Slot)
assert seen_slots["main"](Context(), None, None) == "MAIN_SLOT" # type: ignore[arg-type]
assert isinstance(slots["footer"], Slot)
assert slots["footer"](Context(), None, None) == "FOOTER_SLOT" # type: ignore[arg-type]
assert isinstance(seen_slots["footer"], Slot)
assert seen_slots["footer"](Context(), None, None) == "FOOTER_SLOT" # type: ignore[arg-type]

View file

@ -1,7 +1,5 @@
"""This file tests various ways how the individual tags can be combined inside the templates"""
from typing import Any, Dict, Optional
from django.template import Context, Template
from pytest_django.asserts import assertHTMLEqual
@ -103,9 +101,9 @@ class TestNestedSlot:
</custom-template>
"""
def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]:
def get_template_data(self, args, kwargs, slots, context):
return {
"name": name,
"name": kwargs.get("name", None),
}
registry.clear()
@ -168,8 +166,8 @@ class TestConditionalSlot:
{% endif %}
"""
def get_context_data(self, branch=None):
return {"branch": branch}
def get_template_data(self, args, kwargs, slots, context):
return {"branch": kwargs.get("branch", None)}
return ConditionalComponent
@ -267,9 +265,9 @@ class TestSlotIteration:
{% endfor %}
"""
def get_context_data(self, objects, *args, **kwargs) -> dict:
def get_template_data(self, args, kwargs, slots, context):
return {
"objects": objects,
"objects": kwargs["objects"],
}
return ComponentSimpleSlotInALoop
@ -303,7 +301,7 @@ class TestSlotIteration:
assertHTMLEqual(rendered, expected)
# NOTE: Second arg in tuple is expected result. In isolated mode, while loops should NOT leak,
# we should still have access to root context (returned from get_context_data)
# we should still have access to root context (returned from get_template_data)
@djc_test(
parametrize=(
["components_settings", "expected"],
@ -376,7 +374,7 @@ class TestSlotIteration:
assertHTMLEqual(rendered, expected)
# NOTE: Second arg in tuple is expected result. In isolated mode, while loops should NOT leak,
# we should still have access to root context (returned from get_context_data)
# we should still have access to root context (returned from get_template_data)
@djc_test(
parametrize=(
["components_settings", "expected"],
@ -662,9 +660,9 @@ class TestComponentNesting:
</custom-template>
"""
def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]:
def get_template_data(self, args, kwargs, slots, context):
return {
"name": name,
"name": kwargs.get("name", None),
}
registry.register("test", SlottedComponent)
@ -817,8 +815,8 @@ class TestComponentNesting:
{% endfor %}
"""
def get_context_data(self, items, *args, **kwargs) -> Dict[str, Any]:
return {"items": items}
def get_template_data(self, args, kwargs, slots, context):
return {"items": kwargs["items"]}
template_str: types.django_html = """
{% load component_tags %}