Explorar o código

Fixed #36155 -- Improved error handling when annotate arguments require an alias.

Regression in ed0cbc8d8b314e3b4a0305d0be3cf366d8ee4a74.
Vinko Mlačić hai 1 mes
pai
achega
c6ace896a2
Modificáronse 3 ficheiros con 23 adicións e 2 borrados
  1. 1 0
      AUTHORS
  2. 4 2
      django/db/models/query.py
  3. 18 0
      tests/annotations/tests.py

+ 1 - 0
AUTHORS

@@ -1053,6 +1053,7 @@ answer newbie questions, and generally made Django that much better:
     Vinay Karanam <https://github.com/vinayinvicible>
     Vinay Sajip <vinay_sajip@yahoo.co.uk>
     Vincent Foley <vfoleybourgon@yahoo.ca>
+    Vinko Mlačić <vinkomlacic@outlook.com>
     Vinny Do <vdo.code@gmail.com>
     Vitaly Babiy <vbabiy86@gmail.com>
     Vitaliy Yelnik <velnik@gmail.com>

+ 4 - 2
django/db/models/query.py

@@ -1646,14 +1646,16 @@ class QuerySet(AltersData):
         )
         annotations = {}
         for arg in args:
-            # The default_alias property may raise a TypeError.
+            # The default_alias property raises TypeError if default_alias
+            # can't be set automatically or AttributeError if it isn't an
+            # attribute.
             try:
                 if arg.default_alias in kwargs:
                     raise ValueError(
                         "The named annotation '%s' conflicts with the "
                         "default name for another annotation." % arg.default_alias
                     )
-            except TypeError:
+            except (TypeError, AttributeError):
                 raise TypeError("Complex annotations require an alias")
             annotations[arg.default_alias] = arg
         annotations.update(kwargs)

+ 18 - 0
tests/annotations/tests.py

@@ -969,6 +969,24 @@ class NonAggregateAnnotationTestCase(TestCase):
         ):
             Book.objects.annotate(BooleanField(), Value(False), is_book=True)
 
+    def test_complex_annotations_must_have_an_alias(self):
+        complex_annotations = [
+            F("rating") * F("price"),
+            Value("title"),
+            Case(When(pages__gte=400, then=Value("Long")), default=Value("Short")),
+            Subquery(
+                Book.objects.filter(publisher_id=OuterRef("pk"))
+                .order_by("-pubdate")
+                .values("name")[:1]
+            ),
+            Exists(Book.objects.filter(publisher_id=OuterRef("pk"))),
+        ]
+        msg = "Complex annotations require an alias"
+        for annotation in complex_annotations:
+            with self.subTest(annotation=annotation):
+                with self.assertRaisesMessage(TypeError, msg):
+                    Book.objects.annotate(annotation)
+
     def test_chaining_annotation_filter_with_m2m(self):
         qs = (
             Author.objects.filter(