Skip to content

Commit

Permalink
If wsgi.multiprocess isn't set, render panels on each request.
Browse files Browse the repository at this point in the history
* Avoid an exception with Django-channels

If you apply Django middlewares on a HttpRequest without "wsgi.multiprocess" in META, an exception is raised by DJT. 
This simple patch avoids this bug.

* If wsgi.multiprocess isn't set, render panels on each request.

The likely cause of this is that the application is using ASGI since
wsgi.multiprocess is a required key for a WSGI application. Since the
toolbar currently doesn't support async applications, it's pretty likely
that it won't work for this request.

If you're a developer reading this and you think this is wrong, you can set
the RENDER_PANELS setting to forcibly control this setting.

---------

Co-authored-by: tschilling <schillingt@better-simple.com>
  • Loading branch information
d9pouces and tim-schilling committed May 16, 2023
1 parent 1960ca3 commit af7d15f
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 3 deletions.
10 changes: 7 additions & 3 deletions debug_toolbar/toolbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,13 @@ def should_render_panels(self):
If False, the panels will be loaded via Ajax.
"""
render_panels = self.config["RENDER_PANELS"]
if render_panels is None:
render_panels = self.request.META["wsgi.multiprocess"]
if (render_panels := self.config["RENDER_PANELS"]) is None:
# If wsgi.multiprocess isn't in the headers, then it's likely
# being served by ASGI. This type of set up is most likely
# incompatible with the toolbar until
# https://github.com/jazzband/django-debug-toolbar/issues/1430
# is resolved.
render_panels = self.request.META.get("wsgi.multiprocess", True)
return render_panels

# Handle storing toolbars in memory and fetching them later on
Expand Down
6 changes: 6 additions & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ Pending
presence of other code which also monkey patches those methods.
* Update all timing code that used :py:func:`time.time()` to use
:py:func:`time.perf_counter()` instead.
* Made the check on ``request.META["wsgi.multiprocess"]`` optional, but
defaults to forcing the toolbar to render the panels on each request. This
is because it's likely an ASGI application that's serving the responses
and that's more likely to be an incompatible setup. If you find that this
is incorrect for you in particular, you can use the ``RENDER_PANELS``
setting to forcibly control this logic.

4.0.0 (2023-04-03)
------------------
Expand Down
29 changes: 29 additions & 0 deletions tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,35 @@ def test_show_toolbar_INTERNAL_IPS(self):
with self.settings(INTERNAL_IPS=[]):
self.assertFalse(show_toolbar(self.request))

def test_should_render_panels_RENDER_PANELS(self):
"""
The toolbar should force rendering panels on each request
based on the RENDER_PANELS setting.
"""
toolbar = DebugToolbar(self.request, self.get_response)
self.assertFalse(toolbar.should_render_panels())
toolbar.config["RENDER_PANELS"] = True
self.assertTrue(toolbar.should_render_panels())
toolbar.config["RENDER_PANELS"] = None
self.assertTrue(toolbar.should_render_panels())

def test_should_render_panels_multiprocess(self):
"""
The toolbar should render the panels on each request when wsgi.multiprocess
is True or missing.
"""
request = rf.get("/")
request.META["wsgi.multiprocess"] = True
toolbar = DebugToolbar(request, self.get_response)
toolbar.config["RENDER_PANELS"] = None
self.assertTrue(toolbar.should_render_panels())

request.META["wsgi.multiprocess"] = False
self.assertFalse(toolbar.should_render_panels())

request.META.pop("wsgi.multiprocess")
self.assertTrue(toolbar.should_render_panels())

def _resolve_stats(self, path):
# takes stats from Request panel
self.request.path = path
Expand Down

0 comments on commit af7d15f

Please sign in to comment.