Repository: apache/airflow

Issue:
Mapped KubernetesPodOperater not rendering nested templates
### Apache Airflow version

2.3.3

### What happened

Nested values, such as `env_vars` for the `KubernetesPodOperater` are not being rendered when used as a dynamically mapped operator.

Assuming the following:

```python
op = KubernetesPodOperater.partial(
    env_vars=[k8s.V1EnvVar(name='AWS_ACCESS_KEY_ID', value='{{ var.value.aws_access_key_id }}')],
    # Other arguments
).expand(arguments=[[1], [2]])
```

The *Rendered Template* results for `env_vars` should be:
```
("[{'name': 'AWS_ACCESS_KEY_ID', 'value': 'some-super-secret-value', 'value_from': None}]")
```

Instead the actual *Rendered Template* results for `env_vars` are un-rendered:
```
("[{'name': 'AWS_ACCESS_KEY_ID', 'value': '{{ var.value.aws_access_key_id }}', 'value_from': None}]")
```

This is probably caused by the fact that `MappedOperator` is not calling [`KubernetesPodOperater._render_nested_template_fields`](https://github.com/apache/airflow/blob/main/airflow/providers/cncf/kubernetes/operators/kubernetes_pod.py#L286).

### What you think should happen instead

_No response_

### How to reproduce

_No response_

### Operating System

Ubuntu 18.04

### Versions of Apache Airflow Providers

_No response_

### Deployment

Other 3rd-party Helm chart

### Deployment details

_No response_

### Anything else

_No response_

### Are you willing to submit PR?

- [X] Yes I am willing to submit a PR!

### Code of Conduct

- [X] I agree to follow this project's [Code of Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)



Discussion:
MappedOperator inherits AbstractOperator, which calls `_render_nested_template_fields` via `render_template`. So the analysis seems off.
Does this work?

```python
KubernetesPodOperater(
    task_id=...,
    ...,
    env_vars=[k8s.V1EnvVar(name='AWS_ACCESS_KEY_ID', value='{{ var.value.aws_access_key_id }}')],
)
```
> Does this work?
> 
> ```python
> KubernetesPodOperater(
>     task_id=...,
>     ...,
>     env_vars=[k8s.V1EnvVar(name='AWS_ACCESS_KEY_ID', value='{{ var.value.aws_access_key_id }}')],
> )
> ```

Yes, as mentioned above the issue is only when using the operator as a mapped-operator.

Resolving patch:
diff --git a/airflow/models/mappedoperator.py b/airflow/models/mappedoperator.py
--- a/airflow/models/mappedoperator.py
+++ b/airflow/models/mappedoperator.py
@@ -730,10 +730,11 @@ def run_time_mapped_ti_count(self, run_id: str, *, session: Session) -> Optional
             return None
 
     def _get_template_fields_to_render(self, expanded: Iterable[str]) -> Iterable[str]:
-        # Since the mapped kwargs are already resolved during unmapping,
-        # they must be removed from the list of templated fields to avoid
-        # being rendered again (which breaks escaping).
-        return set(self.template_fields).difference(expanded)
+        # Mapped kwargs from XCom are already resolved during unmapping, so they
+        # must be removed from the list of templated fields to avoid being
+        # rendered again.
+        unexpanded_keys = {k for k, _ in self._get_specified_expand_input().iter_parse_time_resolved_kwargs()}
+        return set(self.template_fields).difference(k for k in expanded if k not in unexpanded_keys)
 
     def render_template_fields(
         self,


Test patch:
diff --git a/tests/models/test_mappedoperator.py b/tests/models/test_mappedoperator.py
--- a/tests/models/test_mappedoperator.py
+++ b/tests/models/test_mappedoperator.py
@@ -313,6 +313,24 @@ def __init__(self, value, arg1, **kwargs):
     assert op.arg2 == "a"
 
 
+def test_mapped_render_nested_template_fields(dag_maker, session):
+    with dag_maker(session=session):
+        MockOperator.partial(task_id="t").expand(arg1=["{{ ti.task_id }}", ["s", "{{ ti.task_id }}"]])
+
+    dr = dag_maker.create_dagrun()
+    decision = dr.task_instance_scheduling_decisions()
+    tis = {(ti.task_id, ti.map_index): ti for ti in decision.schedulable_tis}
+    assert len(tis) == 2
+
+    ti = tis[("t", 0)]
+    ti.run(session=session)
+    assert ti.task.arg1 == "t"
+
+    ti = tis[("t", 1)]
+    ti.run(session=session)
+    assert ti.task.arg1 == ["s", "t"]
+
+
 @pytest.mark.parametrize(
     ["num_existing_tis", "expected"],
     (