Repository: tfranzel/drf-spectacular

Issue:
Serializer context not passed through when forcing serializer to ListSerializer
**Describe the bug**
One of my serializers requires `context["request"]` but spectacular must be throwing away the context when traversing through the serializers. It fails after re-instantiating the serializer with many=True.

https://github.com/tfranzel/drf-spectacular/blob/2cef14d55cda2a3537809a11bf027bba901d97f2/drf_spectacular/plumbing.py#L98-L99

Here it re-instantiates from the class, but does not pass the context through.

**To Reproduce**
Throw an exception in `Serializer.__init__` if context does not contain the request and try to generate a schema for a `Serializer(context={"request": ...)`.

**Expected behavior**
Context is passed through to the instantiated serializer.

Traceback:

```
Traceback (most recent call last):
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/django/views/generic/base.py", line 103, in view
    return self.dispatch(request, *args, **kwargs)
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/rest_framework/views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/rest_framework/views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
    raise exc
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/rest_framework/views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/drf_spectacular/views.py", line 82, in get
    return self._get_schema_response(request)
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/drf_spectacular/views.py", line 90, in _get_schema_response
    data=generator.get_schema(request=request, public=self.serve_public),
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/drf_spectacular/generators.py", line 268, in get_schema
    paths=self.parse(request, public),
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/drf_spectacular/generators.py", line 239, in parse
    operation = view.schema.get_operation(
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/drf_spectacular/utils.py", line 364, in get_operation
    return super().get_operation(path, path_regex, path_prefix, method, registry)
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/drf_spectacular/openapi.py", line 94, in get_operation
    operation['responses'] = self._get_response_bodies()
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/drf_spectacular/openapi.py", line 1275, in _get_response_bodies
    return {'200': self._get_response_for_code(response_serializers, '200', direction=direction)}
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/drf_spectacular/openapi.py", line 1359, in _get_response_for_code
    is_list_serializer_customized(serializer)
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/drf_spectacular/plumbing.py", line 105, in is_list_serializer_customized
    and get_class(get_list_serializer(obj)).to_representation  # type: ignore
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/drf_spectacular/plumbing.py", line 99, in get_list_serializer
    return force_instance(obj) if is_list_serializer(obj) else get_class(obj)(many=True)
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/rest_framework/serializers.py", line 122, in __new__
    return cls.many_init(*args, **kwargs)
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/rest_framework/serializers.py", line 149, in many_init
    child_serializer = cls(*args, **kwargs)
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/rest_access_policy/field_access_mixin.py", line 12, in __init__
    self._apply_fields_access()
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/rest_access_policy/field_access_mixin.py", line 42, in _apply_fields_access
    fields = self.access_policy.scope_fields(self.request, self.fields, instance=self.instance)
  File "/home/brady/.cache/pypoetry/virtualenvs/foo-NLpBhCt1-py3.10/lib/python3.10/site-packages/rest_access_policy/field_access_mixin.py", line 37, in request
    raise Exception("Must pass context with request to FieldAccessMixin")
```

Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/tfranzel/drf-spectacular/pull/828?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=T.+Franzel) Report
Base: **98.68**% // Head: **98.67**% // Decreases project coverage by **`-0.01%`** :warning:
> Coverage data is based on head [(`12ed2c1`)](https://codecov.io/gh/tfranzel/drf-spectacular/pull/828?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=T.+Franzel) compared to base [(`2cef14d`)](https://codecov.io/gh/tfranzel/drf-spectacular/commit/2cef14d55cda2a3537809a11bf027bba901d97f2?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=T.+Franzel).
> Patch coverage: 100.00% of modified lines in pull request are covered.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master     #828      +/-   ##
==========================================
- Coverage   98.68%   98.67%   -0.02%     
==========================================
  Files          66       66              
  Lines        7598     7602       +4     
==========================================
+ Hits         7498     7501       +3     
- Misses        100      101       +1     
```


| [Impacted Files](https://codecov.io/gh/tfranzel/drf-spectacular/pull/828?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=T.+Franzel) | Coverage Δ | |
|---|---|---|
| [drf\_spectacular/plumbing.py](https://codecov.io/gh/tfranzel/drf-spectacular/pull/828/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=T.+Franzel#diff-ZHJmX3NwZWN0YWN1bGFyL3BsdW1iaW5nLnB5) | `97.20% <100.00%> (ø)` | |
| [tests/test\_plumbing.py](https://codecov.io/gh/tfranzel/drf-spectacular/pull/828/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=T.+Franzel#diff-dGVzdHMvdGVzdF9wbHVtYmluZy5weQ==) | `100.00% <100.00%> (ø)` | |
| [tests/test\_fields.py](https://codecov.io/gh/tfranzel/drf-spectacular/pull/828/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=T.+Franzel#diff-dGVzdHMvdGVzdF9maWVsZHMucHk=) | `99.46% <0.00%> (-0.54%)` | :arrow_down: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=T.+Franzel). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=T.+Franzel)

</details>

[:umbrella: View full report at Codecov](https://codecov.io/gh/tfranzel/drf-spectacular/pull/828?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=T.+Franzel).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=T.+Franzel).


Patch:
diff --git a/drf_spectacular/plumbing.py b/drf_spectacular/plumbing.py
index 1932a0f..179d80c 100644
--- a/drf_spectacular/plumbing.py
+++ b/drf_spectacular/plumbing.py
@@ -96,7 +96,7 @@ def is_list_serializer(obj) -> bool:
 
 
 def get_list_serializer(obj):
-    return force_instance(obj) if is_list_serializer(obj) else get_class(obj)(many=True)
+    return force_instance(obj) if is_list_serializer(obj) else get_class(obj)(many=True, context=obj.context)
 
 
 def is_list_serializer_customized(obj) -> bool:


Test patch:
diff --git a/tests/test_plumbing.py b/tests/test_plumbing.py
index ba9365a..47bc0c6 100644
--- a/tests/test_plumbing.py
+++ b/tests/test_plumbing.py
@@ -17,12 +17,18 @@ from drf_spectacular.drainage import TypedDict
 from drf_spectacular.openapi import AutoSchema
 from drf_spectacular.plumbing import (
     analyze_named_regex_pattern, build_basic_type, detype_pattern, follow_field_source,
-    force_instance, is_field, is_serializer, resolve_type_hint,
+    force_instance, get_list_serializer, is_field, is_serializer, resolve_type_hint,
 )
 from drf_spectacular.validation import validate_schema
 from tests import generate_schema
 
 
+def test_get_list_serializer_preserves_context():
+    serializer = serializers.Serializer(context={"foo": "bar"})
+    list_serializer = get_list_serializer(serializer)
+    assert list_serializer.context == {"foo": "bar"}
+
+
 def test_is_serializer():
     assert not is_serializer(serializers.SlugField)
     assert not is_serializer(serializers.SlugField())