1- import os
1+ import posixpath
22import re
3+ import weakref
34
45from django .urls import URLPattern , URLResolver
56from rest_framework import views , viewsets
@@ -106,6 +107,7 @@ def __init__(self, *args, **kwargs):
106107 self .registry = ComponentRegistry ()
107108 self .api_version = kwargs .pop ('api_version' , None )
108109 self .inspector = None
110+ self .schemas_storage = []
109111 super ().__init__ (* args , ** kwargs )
110112
111113 def coerce_path (self , path , method , view ):
@@ -126,7 +128,7 @@ def create_view(self, callback, method, request=None):
126128 decorating plain views like retrieve, this initialization logic is not running.
127129 Therefore forcefully set the schema if @extend_schema decorator was used.
128130 """
129- override_view = OpenApiViewExtension .get_match (callback . cls )
131+ override_view = OpenApiViewExtension .get_match (callback )
130132 if override_view :
131133 original_cls = callback .cls
132134 callback .cls = override_view .view_replacement ()
@@ -179,7 +181,7 @@ def create_view(self, callback, method, request=None):
179181 ) + view_schema_class .__mro__
180182 action_schema_class = type ('ExtendedRearrangedSchema' , mro , {})
181183
182- view . schema = action_schema_class ()
184+ self . _set_schema_to_view ( view , action_schema_class () )
183185 return view
184186
185187 def _initialise_endpoints (self ):
@@ -210,7 +212,7 @@ def parse(self, input_request, public):
210212 # than one view to prevent emission of erroneous and unnecessary fallback names.
211213 non_trivial_prefix = len (set ([view .__class__ for _ , _ , _ , view in endpoints ])) > 1
212214 if non_trivial_prefix :
213- path_prefix = os . path .commonpath ([path for path , _ , _ , _ in endpoints ])
215+ path_prefix = posixpath .commonpath ([path for path , _ , _ , _ in endpoints ])
214216 path_prefix = re .escape (path_prefix ) # guard for RE special chars in path
215217 else :
216218 path_prefix = '/'
@@ -291,3 +293,11 @@ def get_schema(self, request=None, public=False):
291293 result = hook (result = result , generator = self , request = request , public = public )
292294
293295 return sanitize_result_object (normalize_result_object (result ))
296+
297+ def _set_schema_to_view (self , view , schema ):
298+ # The 'schema' argument is used to store the schema and view instance in the global scope,
299+ # as 'schema' is a descriptor. To facilitate garbage collection of these objects,
300+ # we wrap the schema in a weak reference and store it within the SchemaGenerator instance to keep it alive.
301+ # Thus, the lifetime of both the view and the schema is tied to the lifetime of the SchemaGenerator instance.
302+ view .schema = weakref .proxy (schema )
303+ self .schemas_storage .append (schema )
0 commit comments