docs: update section on working with request object (#1126)

* docs: update section on working with request object

* refactor: fix linting
This commit is contained in:
Juro Oravec 2025-04-14 11:35:48 +02:00 committed by GitHub
parent 06cad2ec64
commit fc026cbd99
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 83 additions and 45 deletions

View file

@ -1,25 +1,22 @@
The most common use of django-components is to render HTML for a given request. As such, The most common use of django-components is to render HTML when the server receives a request. As such,
there are a few features that are dependent on the request object. there are a few features that are dependent on the request object.
## Passing and accessing HttpRequest ## Passing the HttpRequest object
In regular Django templates, the request object is available only within the `RequestContext`. In regular Django templates, the request object is available only within the [`RequestContext`](https://docs.djangoproject.com/en/5.2/ref/templates/api/#django.template.RequestContext).
In Components, you can either use `RequestContext`, or pass the `request` object In Components, you can either use [`RequestContext`](https://docs.djangoproject.com/en/5.2/ref/templates/api/#django.template.RequestContext), or pass the `request` object
explicitly to [`Component.render()`](../../../reference/api#django_components.Component.render) and explicitly to [`Component.render()`](../../../reference/api#django_components.Component.render) and
[`Component.render_to_response()`](../../../reference/api#django_components.Component.render_to_response). [`Component.render_to_response()`](../../../reference/api#django_components.Component.render_to_response).
When a component is nested in another, the child component uses parent's `request` object. So the request object is available to components either when:
You can access the request object under [`Component.request`](../../../reference/api#django_components.Component.request): - The component is rendered with [`RequestContext`](https://docs.djangoproject.com/en/5.2/ref/templates/api/#django.template.RequestContext) (Regular Django behavior)
- The component is rendered with a regular [`Context`](https://docs.djangoproject.com/en/5.2/ref/templates/api/#django.template.Context) (or none), but you set the `request` kwarg
of [`Component.render()`](../../../reference/api#django_components.Component.render).
- The component is nested and the parent has access to the request object.
```python ```python
class MyComponent(Component):
def get_context_data(self):
return {
'user_id': self.request.GET['user_id'],
}
# ✅ With request # ✅ With request
MyComponent.render(request=request) MyComponent.render(request=request)
MyComponent.render(context=RequestContext(request, {})) MyComponent.render(context=RequestContext(request, {}))
@ -29,31 +26,7 @@ MyComponent.render()
MyComponent.render(context=Context({})) MyComponent.render(context=Context({}))
``` ```
## Context Processors When a component is rendered within a template with [`{% component %}`](../../../reference/template_tags#component) tag, the request object is available depending on whether the template is rendered with [`RequestContext`](https://docs.djangoproject.com/en/5.2/ref/templates/api/#django.template.RequestContext) or not.
Components support Django's [context processors](https://docs.djangoproject.com/en/5.1/ref/templates/api/#using-requestcontext).
In regular Django templates, the context processors are applied only when the template is rendered with `RequestContext`.
Components allow you to pass the `request` object explicitly. Thus, the context processors are applied to components either when:
- The component is rendered with `RequestContext` (Regular Django behavior)
- The component is rendered with a regular `Context` (or none), but you set the `request` kwarg
of [`Component.render()`](../../../reference/api#django_components.Component.render).
- The component is nested in another component that matches one of the two conditions above.
```python
# ❌ No context processors
rendered = MyComponent.render()
rendered = MyComponent.render(Context({}))
# ✅ With context processors
rendered = MyComponent.render(request=request)
rendered = MyComponent.render(Context({}), request=request)
rendered = MyComponent.render(RequestContext(request, {}))
```
When a component is rendered within a template with [`{% component %}`](../../../reference/template_tags#component) tag, context processors are available depending on whether the template is rendered with `RequestContext` or not.
```python ```python
template = Template(""" template = Template("""
@ -62,13 +35,33 @@ template = Template("""
</div> </div>
""") """)
# ❌ No context processors # ❌ No request
rendered = template.render(Context({})) rendered = template.render(Context({}))
# ✅ With context processors # ✅ With request
rendered = template.render(RequestContext(request, {})) rendered = template.render(RequestContext(request, {}))
``` ```
## Accessing the HttpRequest object
When the component has access to the `request` object, the request object will be available in [`Component.request`](../../../reference/api/#django_components.Component.request).
```python
class MyComponent(Component):
def get_context_data(self):
return {
'user_id': self.request.GET['user_id'],
}
```
## Context Processors
Components support Django's [context processors](https://docs.djangoproject.com/en/5.1/ref/templates/api/#using-requestcontext).
In regular Django templates, the context processors are applied only when the template is rendered with [`RequestContext`](https://docs.djangoproject.com/en/5.2/ref/templates/api/#django.template.RequestContext).
In Components, the context processors are applied when the component has access to the `request` object.
### Accessing context processors data ### Accessing context processors data
The data from context processors is automatically available within the component's template. The data from context processors is automatically available within the component's template.
@ -94,3 +87,11 @@ class MyComponent(Component):
'csrf_token': csrf_token, 'csrf_token': csrf_token,
} }
``` ```
This is a dictionary with the context processors data.
If the request object is not available, then [`self.context_processors_data`](../../../reference/api/#django_components.Component.context_processors_data) will be an empty dictionary.
!!! warning
The [`self.context_processors_data`](../../../reference/api/#django_components.Component.context_processors_data) object is generated dynamically, so changes to it are not persisted.

View file

@ -68,6 +68,7 @@ and [`self.input.kwargs`](../../../reference/api/#django_components.ComponentInp
to access the positional and keyword arguments passed to [`Component.render()`](../../../reference/api/#django_components.Component.render). to access the positional and keyword arguments passed to [`Component.render()`](../../../reference/api/#django_components.Component.render).
```python ```python
class Table(Component):
def get_context_data(self, *args, **kwargs): def get_context_data(self, *args, **kwargs):
# Access component's inputs, slots and context # Access component's inputs, slots and context
assert self.input.args == [123, "str"] assert self.input.args == [123, "str"]
@ -100,6 +101,8 @@ This is a dictionary with the context processors data.
If the request object is not available, then [`self.context_processors_data`](../../../reference/api/#django_components.Component.context_processors_data) will be an empty dictionary. If the request object is not available, then [`self.context_processors_data`](../../../reference/api/#django_components.Component.context_processors_data) will be an empty dictionary.
Read more about the request object and context processors in the [HTTP Request](./http_request.md) section.
```python ```python
from django.http import HttpRequest from django.http import HttpRequest
@ -115,7 +118,3 @@ rendered = Table.render(
request=HttpRequest(), request=HttpRequest(),
) )
``` ```
!!! warning
The [`self.context_processors_data`](../../../reference/api/#django_components.Component.context_processors_data) object is generated dynamically, so changes to it are not persisted.

View file

@ -751,10 +751,48 @@ class Component(
@property @property
def input(self) -> ComponentInput[ArgsType, KwargsType, SlotsType]: def input(self) -> ComponentInput[ArgsType, KwargsType, SlotsType]:
""" """
Input holds the data (like arg, kwargs, slots) that were passed to Input holds the data that were passed to the current component at render time.
the current execution of the `render` method.
Raises `RuntimeError` if accessed outside of rendering execution. Raises `RuntimeError` if accessed outside of rendering execution.
This includes:
- [`args`](../api/#django_components.ComponentInput.args) - List of positional arguments
- [`kwargs`](../api/#django_components.ComponentInput.kwargs) - Dictionary of keyword arguments
- [`slots`](../api/#django_components.ComponentInput.slots) - Dictionary of slots. Values are normalized to
[`Slot`](../api/#django_components.Slot) instances
- [`context`](../api/#django_components.ComponentInput.context) -
[`Context`](https://docs.djangoproject.com/en/5.2/ref/templates/api/#django.template.Context)
object that should be used to render the component
- And other kwargs passed to [`Component.render()`](../api/#django_components.Component.render)
like `type` and `render_dependencies`
Read more on [Component inputs](../../concepts/fundamentals/render_api/#component-inputs).
**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):
# Access component's inputs, slots and context
assert self.input.args == [123, "str"]
assert self.input.kwargs == {"variable": "test", "another": 1}
footer_slot = self.input.slots["footer"]
some_var = self.input.context["some_var"]
return {}
rendered = TestComponent.render(
kwargs={"variable": "test", "another": 1},
args=(123, "str"),
slots={"footer": "MY_SLOT"},
)
```
""" """
if not len(self._metadata_stack): if not len(self._metadata_stack):
raise RuntimeError(f"{self.name}: Tried to access Component input while outside of rendering execution") raise RuntimeError(f"{self.name}: Tried to access Component input while outside of rendering execution")