From aba9c2de669dcc0278c7ffde7981be91801be00b Mon Sep 17 00:00:00 2001 From: Wu Haotian Date: Wed, 30 Jun 2021 18:45:10 +0800 Subject: [PATCH] Fixed #32226 -- Fixed JSON format of QuerySet.explain() on PostgreSQL. --- AUTHORS | 1 + django/db/models/sql/compiler.py | 4 +++- tests/queries/test_explain.py | 8 ++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 6a2224110f..4e4dbc00fd 100644 --- a/AUTHORS +++ b/AUTHORS @@ -974,6 +974,7 @@ answer newbie questions, and generally made Django that much better: Wilson Miner Wim Glenn wojtek + Wu Haotian Xavier Francisco Xia Kai Yann Fouillat diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index 136732bd0b..eda7fc3b5e 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -1,4 +1,5 @@ import collections +import json import re from functools import partial from itertools import chain @@ -1250,9 +1251,10 @@ class SQLCompiler: result = list(self.execute_sql()) # Some backends return 1 item tuples with strings, and others return # tuples with integers and strings. Flatten them out into strings. + output_formatter = json.dumps if self.query.explain_format == 'json' else str for row in result[0]: if not isinstance(row, str): - yield ' '.join(str(c) for c in row) + yield ' '.join(output_formatter(c) for c in row) else: yield row diff --git a/tests/queries/test_explain.py b/tests/queries/test_explain.py index 9bf7de687a..f1108c062f 100644 --- a/tests/queries/test_explain.py +++ b/tests/queries/test_explain.py @@ -1,3 +1,4 @@ +import json import unittest import xml.etree.ElementTree @@ -39,6 +40,13 @@ class ExplainTests(TestCase): self.fail( f'QuerySet.explain() result is not valid XML: {e}' ) + elif format == 'json': + try: + json.loads(result) + except json.JSONDecodeError as e: + self.fail( + f'QuerySet.explain() result is not valid JSON: {e}' + ) @skipUnlessDBFeature('validates_explain_options') def test_unknown_options(self):