(self)
| 13 | @skipUnlessDBFeature("supports_explaining_query_execution") |
| 14 | class ExplainTests(TestCase): |
| 15 | def test_basic(self): |
| 16 | querysets = [ |
| 17 | Tag.objects.filter(name="test"), |
| 18 | Tag.objects.filter(name="test").select_related("parent"), |
| 19 | Tag.objects.filter(name="test").prefetch_related("children"), |
| 20 | Tag.objects.filter(name="test").annotate(Count("children")), |
| 21 | Tag.objects.filter(name="test").values_list("name"), |
| 22 | ] |
| 23 | if connection.features.supports_select_union: |
| 24 | querysets.append( |
| 25 | Tag.objects.order_by().union(Tag.objects.order_by().filter(name="test")) |
| 26 | ) |
| 27 | if connection.features.has_select_for_update: |
| 28 | querysets.append(Tag.objects.select_for_update().filter(name="test")) |
| 29 | supported_formats = connection.features.supported_explain_formats |
| 30 | all_formats = ( |
| 31 | (None,) |
| 32 | + tuple(supported_formats) |
| 33 | + tuple(f.lower() for f in supported_formats) |
| 34 | ) |
| 35 | for idx, queryset in enumerate(querysets): |
| 36 | for format in all_formats: |
| 37 | with self.subTest(format=format, queryset=idx): |
| 38 | with self.assertNumQueries(1) as captured_queries: |
| 39 | result = queryset.explain(format=format) |
| 40 | self.assertTrue( |
| 41 | captured_queries[0]["sql"].startswith( |
| 42 | connection.ops.explain_prefix |
| 43 | ) |
| 44 | ) |
| 45 | self.assertIsInstance(result, str) |
| 46 | self.assertTrue(result) |
| 47 | if not format: |
| 48 | continue |
| 49 | if format.lower() == "xml": |
| 50 | try: |
| 51 | xml.etree.ElementTree.fromstring(result) |
| 52 | except xml.etree.ElementTree.ParseError as e: |
| 53 | self.fail( |
| 54 | f"QuerySet.explain() result is not valid XML: {e}" |
| 55 | ) |
| 56 | elif format.lower() == "json": |
| 57 | try: |
| 58 | json.loads(result) |
| 59 | except json.JSONDecodeError as e: |
| 60 | self.fail( |
| 61 | f"QuerySet.explain() result is not valid JSON: {e}" |
| 62 | ) |
| 63 | |
| 64 | def test_unknown_options(self): |
| 65 | with self.assertRaisesMessage(ValueError, "Unknown options: TEST, TEST2"): |
nothing calls this directly
no test coverage detected