Skip to content

Fix ViewInspector sharing view state across views (#6877) - #10031

Open
abdurrahimcs50 wants to merge 2 commits into
encode:mainfrom
abdurrahimcs50:fix/6877-shared-view-inspector-schema
Open

Fix ViewInspector sharing view state across views (#6877)#10031
abdurrahimcs50 wants to merge 2 commits into
encode:mainfrom
abdurrahimcs50:fix/6877-shared-view-inspector-schema

Conversation

@abdurrahimcs50

Copy link
Copy Markdown

Problem

Fixes #6877.

A single ViewInspector instance (e.g. an AutoSchema assigned via @action(schema=AutoSchema())) can end up attached to multiple views when the action is defined on a mixin that's reused across several ViewSets, since the decorator only evaluates AutoSchema() once, at decoration time.

ViewInspector.__set__ stored view as a plain mutable attribute directly on that shared instance, so each view that touched it during schema generation would overwrite .view for every other view sharing the same instance. The result: schema generation collapses onto whichever view happened to set it last, producing duplicate/incorrect operationIds, descriptions, and request/response schemas for the other views.

Reproduction

class CancelViewSetMixin:
    @action(methods=['post'], detail=True, schema=AutoSchema())
    def cancel(self, request, pk):
        return Response()

class ViewSetA(CancelViewSetMixin, GenericViewSet):
    serializer_class = ASerializer

class ViewSetB(CancelViewSetMixin, GenericViewSet):
    serializer_class = BSerializer

Before this fix, generating the schema for both viewsets produces the same operationId for both cancel actions (and DRF itself warns about the resulting duplicate operationId).

Fix

__set__ now makes a shallow copy.copy() of the schema instance before binding .view to it, so each view gets its own independent copy instead of mutating shared state.

Testing

A single ViewInspector instance (e.g. an AutoSchema assigned via
@action(schema=...)) can end up attached to multiple views when the
action is defined on a mixin reused by several ViewSets. Since `view`
was stored as a plain mutable attribute on the shared instance, each
view that touched it would overwrite `.view` for every other view
sharing it, causing schema generation to collapse onto whichever view
set it last.

__set__ now copies the schema instance per view before binding `view`
to it, so each view gets its own independent copy instead of sharing
mutable state.
The base tox environment doesn't install the optional uritemplate
dependency, and SchemaGenerator.get_schema() asserts on it while
computing path parameters. Guard the new test the same way the rest
of tests/schemas/test_openapi.py already does.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Custom action in a mixin class with custom schema results in incorrect schema generation

1 participant