@@ -49,31 +49,42 @@ def _resolve_http_transforms(
4949 @override
5050 def patch (self , module : ModuleType ) -> None :
5151 """Patch Django by injecting middleware."""
52+ if not self ._try_inject_middleware ():
53+ # Settings not configured yet — defer injection until django.setup() runs
54+ self ._defer_middleware_injection ()
55+
56+ def _try_inject_middleware (self ) -> bool :
57+ """Attempt to inject DriftMiddleware into Django settings.
58+
59+ Returns:
60+ True if middleware was injected (or already present), False if
61+ settings are not yet configured and injection should be deferred.
62+ """
5263 global _middleware_injected
5364
5465 if _middleware_injected :
5566 logger .debug ("Middleware already injected, skipping" )
56- return
67+ return True
5768
5869 try :
5970 from django .conf import settings
6071
6172 if not settings .configured :
62- logger .warning ("Django settings not configured, cannot inject middleware" )
63- return
73+ logger .debug ("Django settings not configured yet, will defer middleware injection " )
74+ return False
6475
6576 middleware_setting = self ._get_middleware_setting (settings )
6677 if not middleware_setting :
6778 logger .warning ("Could not find middleware setting, cannot inject" )
68- return
79+ return True # Don't retry — this won't change
6980
7081 current_middleware = list (getattr (settings , middleware_setting , []))
7182
7283 middleware_path = "drift.instrumentation.django.middleware.DriftMiddleware"
7384 if middleware_path in current_middleware :
7485 logger .debug ("DriftMiddleware already in settings, skipping injection" )
7586 _middleware_injected = True
76- return
87+ return True
7788
7889 # Insert at position 0 to capture all requests
7990 current_middleware .insert (0 , middleware_path )
@@ -89,11 +100,38 @@ def patch(self, module: ModuleType) -> None:
89100 self ._force_database_reconnect ()
90101
91102 print ("Django instrumentation applied" )
103+ return True
92104
93105 except ImportError as e :
94106 logger .warning (f"Could not import Django settings: { e } " )
107+ return True # Don't retry on import errors
95108 except Exception as e :
96109 logger .error (f"Failed to inject middleware: { e } " , exc_info = True )
110+ return True # Don't retry on unexpected errors
111+
112+ def _defer_middleware_injection (self ) -> None :
113+ """Monkey-patch django.setup() to inject middleware after settings are configured.
114+
115+ When TuskDrift.initialize() runs before DJANGO_SETTINGS_MODULE is set
116+ (common in manage.py where the SDK init is the first import), Django
117+ settings aren't available yet. This defers injection to run after
118+ django.setup() completes, which is when settings are guaranteed to be
119+ configured.
120+ """
121+ import django
122+
123+ original_setup = django .setup
124+
125+ def patched_setup (* args , ** kwargs ):
126+ try :
127+ result = original_setup (* args , ** kwargs )
128+ self ._try_inject_middleware ()
129+ return result
130+ finally :
131+ django .setup = original_setup
132+
133+ django .setup = patched_setup # ty: ignore[invalid-assignment]
134+ logger .debug ("Deferred middleware injection to django.setup()" )
97135
98136 def _force_database_reconnect (self ) -> None :
99137 """Force Django to close and recreate database connections."""
0 commit comments