1. import datetime
    
  2. from decimal import Decimal
    
  3. 
    
  4. from django.core.exceptions import FieldDoesNotExist, FieldError
    
  5. from django.db.models import (
    
  6.     BooleanField,
    
  7.     Case,
    
  8.     CharField,
    
  9.     Count,
    
  10.     DateTimeField,
    
  11.     DecimalField,
    
  12.     Exists,
    
  13.     ExpressionWrapper,
    
  14.     F,
    
  15.     FloatField,
    
  16.     Func,
    
  17.     IntegerField,
    
  18.     Max,
    
  19.     OuterRef,
    
  20.     Q,
    
  21.     Subquery,
    
  22.     Sum,
    
  23.     Value,
    
  24.     When,
    
  25. )
    
  26. from django.db.models.expressions import RawSQL
    
  27. from django.db.models.functions import Coalesce, ExtractYear, Floor, Length, Lower, Trim
    
  28. from django.test import TestCase, skipUnlessDBFeature
    
  29. from django.test.utils import register_lookup
    
  30. 
    
  31. from .models import (
    
  32.     Author,
    
  33.     Book,
    
  34.     Company,
    
  35.     DepartmentStore,
    
  36.     Employee,
    
  37.     Publisher,
    
  38.     Store,
    
  39.     Ticket,
    
  40. )
    
  41. 
    
  42. 
    
  43. class NonAggregateAnnotationTestCase(TestCase):
    
  44.     @classmethod
    
  45.     def setUpTestData(cls):
    
  46.         cls.a1 = Author.objects.create(name="Adrian Holovaty", age=34)
    
  47.         cls.a2 = Author.objects.create(name="Jacob Kaplan-Moss", age=35)
    
  48.         cls.a3 = Author.objects.create(name="Brad Dayley", age=45)
    
  49.         cls.a4 = Author.objects.create(name="James Bennett", age=29)
    
  50.         cls.a5 = Author.objects.create(name="Jeffrey Forcier", age=37)
    
  51.         cls.a6 = Author.objects.create(name="Paul Bissex", age=29)
    
  52.         cls.a7 = Author.objects.create(name="Wesley J. Chun", age=25)
    
  53.         cls.a8 = Author.objects.create(name="Peter Norvig", age=57)
    
  54.         cls.a9 = Author.objects.create(name="Stuart Russell", age=46)
    
  55.         cls.a1.friends.add(cls.a2, cls.a4)
    
  56.         cls.a2.friends.add(cls.a1, cls.a7)
    
  57.         cls.a4.friends.add(cls.a1)
    
  58.         cls.a5.friends.add(cls.a6, cls.a7)
    
  59.         cls.a6.friends.add(cls.a5, cls.a7)
    
  60.         cls.a7.friends.add(cls.a2, cls.a5, cls.a6)
    
  61.         cls.a8.friends.add(cls.a9)
    
  62.         cls.a9.friends.add(cls.a8)
    
  63. 
    
  64.         cls.p1 = Publisher.objects.create(name="Apress", num_awards=3)
    
  65.         cls.p2 = Publisher.objects.create(name="Sams", num_awards=1)
    
  66.         cls.p3 = Publisher.objects.create(name="Prentice Hall", num_awards=7)
    
  67.         cls.p4 = Publisher.objects.create(name="Morgan Kaufmann", num_awards=9)
    
  68.         cls.p5 = Publisher.objects.create(name="Jonno's House of Books", num_awards=0)
    
  69. 
    
  70.         cls.b1 = Book.objects.create(
    
  71.             isbn="159059725",
    
  72.             name="The Definitive Guide to Django: Web Development Done Right",
    
  73.             pages=447,
    
  74.             rating=4.5,
    
  75.             price=Decimal("30.00"),
    
  76.             contact=cls.a1,
    
  77.             publisher=cls.p1,
    
  78.             pubdate=datetime.date(2007, 12, 6),
    
  79.         )
    
  80.         cls.b2 = Book.objects.create(
    
  81.             isbn="067232959",
    
  82.             name="Sams Teach Yourself Django in 24 Hours",
    
  83.             pages=528,
    
  84.             rating=3.0,
    
  85.             price=Decimal("23.09"),
    
  86.             contact=cls.a3,
    
  87.             publisher=cls.p2,
    
  88.             pubdate=datetime.date(2008, 3, 3),
    
  89.         )
    
  90.         cls.b3 = Book.objects.create(
    
  91.             isbn="159059996",
    
  92.             name="Practical Django Projects",
    
  93.             pages=300,
    
  94.             rating=4.0,
    
  95.             price=Decimal("29.69"),
    
  96.             contact=cls.a4,
    
  97.             publisher=cls.p1,
    
  98.             pubdate=datetime.date(2008, 6, 23),
    
  99.         )
    
  100.         cls.b4 = Book.objects.create(
    
  101.             isbn="013235613",
    
  102.             name="Python Web Development with Django",
    
  103.             pages=350,
    
  104.             rating=4.0,
    
  105.             price=Decimal("29.69"),
    
  106.             contact=cls.a5,
    
  107.             publisher=cls.p3,
    
  108.             pubdate=datetime.date(2008, 11, 3),
    
  109.         )
    
  110.         cls.b5 = Book.objects.create(
    
  111.             isbn="013790395",
    
  112.             name="Artificial Intelligence: A Modern Approach",
    
  113.             pages=1132,
    
  114.             rating=4.0,
    
  115.             price=Decimal("82.80"),
    
  116.             contact=cls.a8,
    
  117.             publisher=cls.p3,
    
  118.             pubdate=datetime.date(1995, 1, 15),
    
  119.         )
    
  120.         cls.b6 = Book.objects.create(
    
  121.             isbn="155860191",
    
  122.             name=(
    
  123.                 "Paradigms of Artificial Intelligence Programming: Case Studies in "
    
  124.                 "Common Lisp"
    
  125.             ),
    
  126.             pages=946,
    
  127.             rating=5.0,
    
  128.             price=Decimal("75.00"),
    
  129.             contact=cls.a8,
    
  130.             publisher=cls.p4,
    
  131.             pubdate=datetime.date(1991, 10, 15),
    
  132.         )
    
  133.         cls.b1.authors.add(cls.a1, cls.a2)
    
  134.         cls.b2.authors.add(cls.a3)
    
  135.         cls.b3.authors.add(cls.a4)
    
  136.         cls.b4.authors.add(cls.a5, cls.a6, cls.a7)
    
  137.         cls.b5.authors.add(cls.a8, cls.a9)
    
  138.         cls.b6.authors.add(cls.a8)
    
  139. 
    
  140.         cls.s1 = Store.objects.create(
    
  141.             name="Amazon.com",
    
  142.             original_opening=datetime.datetime(1994, 4, 23, 9, 17, 42),
    
  143.             friday_night_closing=datetime.time(23, 59, 59),
    
  144.         )
    
  145.         cls.s2 = Store.objects.create(
    
  146.             name="Books.com",
    
  147.             original_opening=datetime.datetime(2001, 3, 15, 11, 23, 37),
    
  148.             friday_night_closing=datetime.time(23, 59, 59),
    
  149.         )
    
  150.         cls.s3 = Store.objects.create(
    
  151.             name="Mamma and Pappa's Books",
    
  152.             original_opening=datetime.datetime(1945, 4, 25, 16, 24, 14),
    
  153.             friday_night_closing=datetime.time(21, 30),
    
  154.         )
    
  155.         cls.s1.books.add(cls.b1, cls.b2, cls.b3, cls.b4, cls.b5, cls.b6)
    
  156.         cls.s2.books.add(cls.b1, cls.b3, cls.b5, cls.b6)
    
  157.         cls.s3.books.add(cls.b3, cls.b4, cls.b6)
    
  158. 
    
  159.     def test_basic_annotation(self):
    
  160.         books = Book.objects.annotate(is_book=Value(1))
    
  161.         for book in books:
    
  162.             self.assertEqual(book.is_book, 1)
    
  163. 
    
  164.     def test_basic_f_annotation(self):
    
  165.         books = Book.objects.annotate(another_rating=F("rating"))
    
  166.         for book in books:
    
  167.             self.assertEqual(book.another_rating, book.rating)
    
  168. 
    
  169.     def test_joined_annotation(self):
    
  170.         books = Book.objects.select_related("publisher").annotate(
    
  171.             num_awards=F("publisher__num_awards")
    
  172.         )
    
  173.         for book in books:
    
  174.             self.assertEqual(book.num_awards, book.publisher.num_awards)
    
  175. 
    
  176.     def test_joined_transformed_annotation(self):
    
  177.         Employee.objects.bulk_create(
    
  178.             [
    
  179.                 Employee(
    
  180.                     first_name="John",
    
  181.                     last_name="Doe",
    
  182.                     age=18,
    
  183.                     store=self.s1,
    
  184.                     salary=15000,
    
  185.                 ),
    
  186.                 Employee(
    
  187.                     first_name="Jane",
    
  188.                     last_name="Jones",
    
  189.                     age=30,
    
  190.                     store=self.s2,
    
  191.                     salary=30000,
    
  192.                 ),
    
  193.                 Employee(
    
  194.                     first_name="Jo",
    
  195.                     last_name="Smith",
    
  196.                     age=55,
    
  197.                     store=self.s3,
    
  198.                     salary=50000,
    
  199.                 ),
    
  200.             ]
    
  201.         )
    
  202.         employees = Employee.objects.annotate(
    
  203.             store_opened_year=F("store__original_opening__year"),
    
  204.         )
    
  205.         for employee in employees:
    
  206.             self.assertEqual(
    
  207.                 employee.store_opened_year,
    
  208.                 employee.store.original_opening.year,
    
  209.             )
    
  210. 
    
  211.     def test_custom_transform_annotation(self):
    
  212.         with register_lookup(DecimalField, Floor):
    
  213.             books = Book.objects.annotate(floor_price=F("price__floor"))
    
  214. 
    
  215.         self.assertCountEqual(
    
  216.             books.values_list("pk", "floor_price"),
    
  217.             [
    
  218.                 (self.b1.pk, 30),
    
  219.                 (self.b2.pk, 23),
    
  220.                 (self.b3.pk, 29),
    
  221.                 (self.b4.pk, 29),
    
  222.                 (self.b5.pk, 82),
    
  223.                 (self.b6.pk, 75),
    
  224.             ],
    
  225.         )
    
  226. 
    
  227.     def test_chaining_transforms(self):
    
  228.         Company.objects.create(name=" Django Software Foundation  ")
    
  229.         Company.objects.create(name="Yahoo")
    
  230.         with register_lookup(CharField, Trim), register_lookup(CharField, Length):
    
  231.             for expr in [Length("name__trim"), F("name__trim__length")]:
    
  232.                 with self.subTest(expr=expr):
    
  233.                     self.assertCountEqual(
    
  234.                         Company.objects.annotate(length=expr).values("name", "length"),
    
  235.                         [
    
  236.                             {"name": " Django Software Foundation  ", "length": 26},
    
  237.                             {"name": "Yahoo", "length": 5},
    
  238.                         ],
    
  239.                     )
    
  240. 
    
  241.     def test_mixed_type_annotation_date_interval(self):
    
  242.         active = datetime.datetime(2015, 3, 20, 14, 0, 0)
    
  243.         duration = datetime.timedelta(hours=1)
    
  244.         expires = datetime.datetime(2015, 3, 20, 14, 0, 0) + duration
    
  245.         Ticket.objects.create(active_at=active, duration=duration)
    
  246.         t = Ticket.objects.annotate(
    
  247.             expires=ExpressionWrapper(
    
  248.                 F("active_at") + F("duration"), output_field=DateTimeField()
    
  249.             )
    
  250.         ).first()
    
  251.         self.assertEqual(t.expires, expires)
    
  252. 
    
  253.     def test_mixed_type_annotation_numbers(self):
    
  254.         test = self.b1
    
  255.         b = Book.objects.annotate(
    
  256.             combined=ExpressionWrapper(
    
  257.                 F("pages") + F("rating"), output_field=IntegerField()
    
  258.             )
    
  259.         ).get(isbn=test.isbn)
    
  260.         combined = int(test.pages + test.rating)
    
  261.         self.assertEqual(b.combined, combined)
    
  262. 
    
  263.     def test_empty_expression_annotation(self):
    
  264.         books = Book.objects.annotate(
    
  265.             selected=ExpressionWrapper(Q(pk__in=[]), output_field=BooleanField())
    
  266.         )
    
  267.         self.assertEqual(len(books), Book.objects.count())
    
  268.         self.assertTrue(all(not book.selected for book in books))
    
  269. 
    
  270.         books = Book.objects.annotate(
    
  271.             selected=ExpressionWrapper(
    
  272.                 Q(pk__in=Book.objects.none()), output_field=BooleanField()
    
  273.             )
    
  274.         )
    
  275.         self.assertEqual(len(books), Book.objects.count())
    
  276.         self.assertTrue(all(not book.selected for book in books))
    
  277. 
    
  278.     def test_full_expression_annotation(self):
    
  279.         books = Book.objects.annotate(
    
  280.             selected=ExpressionWrapper(~Q(pk__in=[]), output_field=BooleanField()),
    
  281.         )
    
  282.         self.assertEqual(len(books), Book.objects.count())
    
  283.         self.assertTrue(all(book.selected for book in books))
    
  284. 
    
  285.     def test_full_expression_annotation_with_aggregation(self):
    
  286.         qs = Book.objects.filter(isbn="159059725").annotate(
    
  287.             selected=ExpressionWrapper(~Q(pk__in=[]), output_field=BooleanField()),
    
  288.             rating_count=Count("rating"),
    
  289.         )
    
  290.         self.assertEqual([book.rating_count for book in qs], [1])
    
  291. 
    
  292.     def test_aggregate_over_full_expression_annotation(self):
    
  293.         qs = Book.objects.annotate(
    
  294.             selected=ExpressionWrapper(~Q(pk__in=[]), output_field=BooleanField()),
    
  295.         ).aggregate(Sum("selected"))
    
  296.         self.assertEqual(qs["selected__sum"], Book.objects.count())
    
  297. 
    
  298.     def test_empty_queryset_annotation(self):
    
  299.         qs = Author.objects.annotate(empty=Subquery(Author.objects.values("id").none()))
    
  300.         self.assertIsNone(qs.first().empty)
    
  301. 
    
  302.     def test_annotate_with_aggregation(self):
    
  303.         books = Book.objects.annotate(is_book=Value(1), rating_count=Count("rating"))
    
  304.         for book in books:
    
  305.             self.assertEqual(book.is_book, 1)
    
  306.             self.assertEqual(book.rating_count, 1)
    
  307. 
    
  308.     def test_combined_expression_annotation_with_aggregation(self):
    
  309.         book = Book.objects.annotate(
    
  310.             combined=ExpressionWrapper(
    
  311.                 Value(3) * Value(4), output_field=IntegerField()
    
  312.             ),
    
  313.             rating_count=Count("rating"),
    
  314.         ).first()
    
  315.         self.assertEqual(book.combined, 12)
    
  316.         self.assertEqual(book.rating_count, 1)
    
  317. 
    
  318.     def test_combined_f_expression_annotation_with_aggregation(self):
    
  319.         book = (
    
  320.             Book.objects.filter(isbn="159059725")
    
  321.             .annotate(
    
  322.                 combined=ExpressionWrapper(
    
  323.                     F("price") * F("pages"), output_field=FloatField()
    
  324.                 ),
    
  325.                 rating_count=Count("rating"),
    
  326.             )
    
  327.             .first()
    
  328.         )
    
  329.         self.assertEqual(book.combined, 13410.0)
    
  330.         self.assertEqual(book.rating_count, 1)
    
  331. 
    
  332.     @skipUnlessDBFeature("supports_boolean_expr_in_select_clause")
    
  333.     def test_q_expression_annotation_with_aggregation(self):
    
  334.         book = (
    
  335.             Book.objects.filter(isbn="159059725")
    
  336.             .annotate(
    
  337.                 isnull_pubdate=ExpressionWrapper(
    
  338.                     Q(pubdate__isnull=True),
    
  339.                     output_field=BooleanField(),
    
  340.                 ),
    
  341.                 rating_count=Count("rating"),
    
  342.             )
    
  343.             .first()
    
  344.         )
    
  345.         self.assertIs(book.isnull_pubdate, False)
    
  346.         self.assertEqual(book.rating_count, 1)
    
  347. 
    
  348.     @skipUnlessDBFeature("supports_boolean_expr_in_select_clause")
    
  349.     def test_grouping_by_q_expression_annotation(self):
    
  350.         authors = (
    
  351.             Author.objects.annotate(
    
  352.                 under_40=ExpressionWrapper(Q(age__lt=40), output_field=BooleanField()),
    
  353.             )
    
  354.             .values("under_40")
    
  355.             .annotate(
    
  356.                 count_id=Count("id"),
    
  357.             )
    
  358.             .values("under_40", "count_id")
    
  359.         )
    
  360.         self.assertCountEqual(
    
  361.             authors,
    
  362.             [
    
  363.                 {"under_40": False, "count_id": 3},
    
  364.                 {"under_40": True, "count_id": 6},
    
  365.             ],
    
  366.         )
    
  367. 
    
  368.     def test_aggregate_over_annotation(self):
    
  369.         agg = Author.objects.annotate(other_age=F("age")).aggregate(
    
  370.             otherage_sum=Sum("other_age")
    
  371.         )
    
  372.         other_agg = Author.objects.aggregate(age_sum=Sum("age"))
    
  373.         self.assertEqual(agg["otherage_sum"], other_agg["age_sum"])
    
  374. 
    
  375.     @skipUnlessDBFeature("can_distinct_on_fields")
    
  376.     def test_distinct_on_with_annotation(self):
    
  377.         store = Store.objects.create(
    
  378.             name="test store",
    
  379.             original_opening=datetime.datetime.now(),
    
  380.             friday_night_closing=datetime.time(21, 00, 00),
    
  381.         )
    
  382.         names = [
    
  383.             "Theodore Roosevelt",
    
  384.             "Eleanor Roosevelt",
    
  385.             "Franklin Roosevelt",
    
  386.             "Ned Stark",
    
  387.             "Catelyn Stark",
    
  388.         ]
    
  389.         for name in names:
    
  390.             Employee.objects.create(
    
  391.                 store=store,
    
  392.                 first_name=name.split()[0],
    
  393.                 last_name=name.split()[1],
    
  394.                 age=30,
    
  395.                 salary=2000,
    
  396.             )
    
  397. 
    
  398.         people = Employee.objects.annotate(
    
  399.             name_lower=Lower("last_name"),
    
  400.         ).distinct("name_lower")
    
  401. 
    
  402.         self.assertEqual({p.last_name for p in people}, {"Stark", "Roosevelt"})
    
  403.         self.assertEqual(len(people), 2)
    
  404. 
    
  405.         people2 = Employee.objects.annotate(
    
  406.             test_alias=F("store__name"),
    
  407.         ).distinct("test_alias")
    
  408.         self.assertEqual(len(people2), 1)
    
  409. 
    
  410.         lengths = (
    
  411.             Employee.objects.annotate(
    
  412.                 name_len=Length("first_name"),
    
  413.             )
    
  414.             .distinct("name_len")
    
  415.             .values_list("name_len", flat=True)
    
  416.         )
    
  417.         self.assertCountEqual(lengths, [3, 7, 8])
    
  418. 
    
  419.     def test_filter_annotation(self):
    
  420.         books = Book.objects.annotate(is_book=Value(1)).filter(is_book=1)
    
  421.         for book in books:
    
  422.             self.assertEqual(book.is_book, 1)
    
  423. 
    
  424.     def test_filter_annotation_with_f(self):
    
  425.         books = Book.objects.annotate(other_rating=F("rating")).filter(other_rating=3.5)
    
  426.         for book in books:
    
  427.             self.assertEqual(book.other_rating, 3.5)
    
  428. 
    
  429.     def test_filter_annotation_with_double_f(self):
    
  430.         books = Book.objects.annotate(other_rating=F("rating")).filter(
    
  431.             other_rating=F("rating")
    
  432.         )
    
  433.         for book in books:
    
  434.             self.assertEqual(book.other_rating, book.rating)
    
  435. 
    
  436.     def test_filter_agg_with_double_f(self):
    
  437.         books = Book.objects.annotate(sum_rating=Sum("rating")).filter(
    
  438.             sum_rating=F("sum_rating")
    
  439.         )
    
  440.         for book in books:
    
  441.             self.assertEqual(book.sum_rating, book.rating)
    
  442. 
    
  443.     def test_filter_wrong_annotation(self):
    
  444.         with self.assertRaisesMessage(
    
  445.             FieldError, "Cannot resolve keyword 'nope' into field."
    
  446.         ):
    
  447.             list(
    
  448.                 Book.objects.annotate(sum_rating=Sum("rating")).filter(
    
  449.                     sum_rating=F("nope")
    
  450.                 )
    
  451.             )
    
  452. 
    
  453.     def test_decimal_annotation(self):
    
  454.         salary = Decimal(10) ** -Employee._meta.get_field("salary").decimal_places
    
  455.         Employee.objects.create(
    
  456.             first_name="Max",
    
  457.             last_name="Paine",
    
  458.             store=Store.objects.first(),
    
  459.             age=23,
    
  460.             salary=salary,
    
  461.         )
    
  462.         self.assertEqual(
    
  463.             Employee.objects.annotate(new_salary=F("salary") / 10).get().new_salary,
    
  464.             salary / 10,
    
  465.         )
    
  466. 
    
  467.     def test_filter_decimal_annotation(self):
    
  468.         qs = (
    
  469.             Book.objects.annotate(new_price=F("price") + 1)
    
  470.             .filter(new_price=Decimal(31))
    
  471.             .values_list("new_price")
    
  472.         )
    
  473.         self.assertEqual(qs.get(), (Decimal(31),))
    
  474. 
    
  475.     def test_combined_annotation_commutative(self):
    
  476.         book1 = Book.objects.annotate(adjusted_rating=F("rating") + 2).get(
    
  477.             pk=self.b1.pk
    
  478.         )
    
  479.         book2 = Book.objects.annotate(adjusted_rating=2 + F("rating")).get(
    
  480.             pk=self.b1.pk
    
  481.         )
    
  482.         self.assertEqual(book1.adjusted_rating, book2.adjusted_rating)
    
  483.         book1 = Book.objects.annotate(adjusted_rating=F("rating") + None).get(
    
  484.             pk=self.b1.pk
    
  485.         )
    
  486.         book2 = Book.objects.annotate(adjusted_rating=None + F("rating")).get(
    
  487.             pk=self.b1.pk
    
  488.         )
    
  489.         self.assertIs(book1.adjusted_rating, None)
    
  490.         self.assertEqual(book1.adjusted_rating, book2.adjusted_rating)
    
  491. 
    
  492.     def test_update_with_annotation(self):
    
  493.         book_preupdate = Book.objects.get(pk=self.b2.pk)
    
  494.         Book.objects.annotate(other_rating=F("rating") - 1).update(
    
  495.             rating=F("other_rating")
    
  496.         )
    
  497.         book_postupdate = Book.objects.get(pk=self.b2.pk)
    
  498.         self.assertEqual(book_preupdate.rating - 1, book_postupdate.rating)
    
  499. 
    
  500.     def test_annotation_with_m2m(self):
    
  501.         books = (
    
  502.             Book.objects.annotate(author_age=F("authors__age"))
    
  503.             .filter(pk=self.b1.pk)
    
  504.             .order_by("author_age")
    
  505.         )
    
  506.         self.assertEqual(books[0].author_age, 34)
    
  507.         self.assertEqual(books[1].author_age, 35)
    
  508. 
    
  509.     def test_annotation_reverse_m2m(self):
    
  510.         books = (
    
  511.             Book.objects.annotate(
    
  512.                 store_name=F("store__name"),
    
  513.             )
    
  514.             .filter(
    
  515.                 name="Practical Django Projects",
    
  516.             )
    
  517.             .order_by("store_name")
    
  518.         )
    
  519. 
    
  520.         self.assertQuerysetEqual(
    
  521.             books,
    
  522.             ["Amazon.com", "Books.com", "Mamma and Pappa's Books"],
    
  523.             lambda b: b.store_name,
    
  524.         )
    
  525. 
    
  526.     def test_values_annotation(self):
    
  527.         """
    
  528.         Annotations can reference fields in a values clause,
    
  529.         and contribute to an existing values clause.
    
  530.         """
    
  531.         # annotate references a field in values()
    
  532.         qs = Book.objects.values("rating").annotate(other_rating=F("rating") - 1)
    
  533.         book = qs.get(pk=self.b1.pk)
    
  534.         self.assertEqual(book["rating"] - 1, book["other_rating"])
    
  535. 
    
  536.         # filter refs the annotated value
    
  537.         book = qs.get(other_rating=4)
    
  538.         self.assertEqual(book["other_rating"], 4)
    
  539. 
    
  540.         # can annotate an existing values with a new field
    
  541.         book = qs.annotate(other_isbn=F("isbn")).get(other_rating=4)
    
  542.         self.assertEqual(book["other_rating"], 4)
    
  543.         self.assertEqual(book["other_isbn"], "155860191")
    
  544. 
    
  545.     def test_values_with_pk_annotation(self):
    
  546.         # annotate references a field in values() with pk
    
  547.         publishers = Publisher.objects.values("id", "book__rating").annotate(
    
  548.             total=Sum("book__rating")
    
  549.         )
    
  550.         for publisher in publishers.filter(pk=self.p1.pk):
    
  551.             self.assertEqual(publisher["book__rating"], publisher["total"])
    
  552. 
    
  553.     @skipUnlessDBFeature("allows_group_by_pk")
    
  554.     def test_rawsql_group_by_collapse(self):
    
  555.         raw = RawSQL("SELECT MIN(id) FROM annotations_book", [])
    
  556.         qs = (
    
  557.             Author.objects.values("id")
    
  558.             .annotate(
    
  559.                 min_book_id=raw,
    
  560.                 count_friends=Count("friends"),
    
  561.             )
    
  562.             .order_by()
    
  563.         )
    
  564.         _, _, group_by = qs.query.get_compiler(using="default").pre_sql_setup()
    
  565.         self.assertEqual(len(group_by), 1)
    
  566.         self.assertNotEqual(raw, group_by[0])
    
  567. 
    
  568.     def test_defer_annotation(self):
    
  569.         """
    
  570.         Deferred attributes can be referenced by an annotation,
    
  571.         but they are not themselves deferred, and cannot be deferred.
    
  572.         """
    
  573.         qs = Book.objects.defer("rating").annotate(other_rating=F("rating") - 1)
    
  574. 
    
  575.         with self.assertNumQueries(2):
    
  576.             book = qs.get(other_rating=4)
    
  577.             self.assertEqual(book.rating, 5)
    
  578.             self.assertEqual(book.other_rating, 4)
    
  579. 
    
  580.         with self.assertRaisesMessage(
    
  581.             FieldDoesNotExist, "Book has no field named 'other_rating'"
    
  582.         ):
    
  583.             book = qs.defer("other_rating").get(other_rating=4)
    
  584. 
    
  585.     def test_mti_annotations(self):
    
  586.         """
    
  587.         Fields on an inherited model can be referenced by an
    
  588.         annotated field.
    
  589.         """
    
  590.         d = DepartmentStore.objects.create(
    
  591.             name="Angus & Robinson",
    
  592.             original_opening=datetime.date(2014, 3, 8),
    
  593.             friday_night_closing=datetime.time(21, 00, 00),
    
  594.             chain="Westfield",
    
  595.         )
    
  596. 
    
  597.         books = Book.objects.filter(rating__gt=4)
    
  598.         for b in books:
    
  599.             d.books.add(b)
    
  600. 
    
  601.         qs = (
    
  602.             DepartmentStore.objects.annotate(
    
  603.                 other_name=F("name"),
    
  604.                 other_chain=F("chain"),
    
  605.                 is_open=Value(True, BooleanField()),
    
  606.                 book_isbn=F("books__isbn"),
    
  607.             )
    
  608.             .order_by("book_isbn")
    
  609.             .filter(chain="Westfield")
    
  610.         )
    
  611. 
    
  612.         self.assertQuerysetEqual(
    
  613.             qs,
    
  614.             [
    
  615.                 ("Angus & Robinson", "Westfield", True, "155860191"),
    
  616.                 ("Angus & Robinson", "Westfield", True, "159059725"),
    
  617.             ],
    
  618.             lambda d: (d.other_name, d.other_chain, d.is_open, d.book_isbn),
    
  619.         )
    
  620. 
    
  621.     def test_null_annotation(self):
    
  622.         """
    
  623.         Annotating None onto a model round-trips
    
  624.         """
    
  625.         book = Book.objects.annotate(
    
  626.             no_value=Value(None, output_field=IntegerField())
    
  627.         ).first()
    
  628.         self.assertIsNone(book.no_value)
    
  629. 
    
  630.     def test_order_by_annotation(self):
    
  631.         authors = Author.objects.annotate(other_age=F("age")).order_by("other_age")
    
  632.         self.assertQuerysetEqual(
    
  633.             authors,
    
  634.             [
    
  635.                 25,
    
  636.                 29,
    
  637.                 29,
    
  638.                 34,
    
  639.                 35,
    
  640.                 37,
    
  641.                 45,
    
  642.                 46,
    
  643.                 57,
    
  644.             ],
    
  645.             lambda a: a.other_age,
    
  646.         )
    
  647. 
    
  648.     def test_order_by_aggregate(self):
    
  649.         authors = (
    
  650.             Author.objects.values("age")
    
  651.             .annotate(age_count=Count("age"))
    
  652.             .order_by("age_count", "age")
    
  653.         )
    
  654.         self.assertQuerysetEqual(
    
  655.             authors,
    
  656.             [
    
  657.                 (25, 1),
    
  658.                 (34, 1),
    
  659.                 (35, 1),
    
  660.                 (37, 1),
    
  661.                 (45, 1),
    
  662.                 (46, 1),
    
  663.                 (57, 1),
    
  664.                 (29, 2),
    
  665.             ],
    
  666.             lambda a: (a["age"], a["age_count"]),
    
  667.         )
    
  668. 
    
  669.     def test_raw_sql_with_inherited_field(self):
    
  670.         DepartmentStore.objects.create(
    
  671.             name="Angus & Robinson",
    
  672.             original_opening=datetime.date(2014, 3, 8),
    
  673.             friday_night_closing=datetime.time(21),
    
  674.             chain="Westfield",
    
  675.             area=123,
    
  676.         )
    
  677.         tests = (
    
  678.             ("name", "Angus & Robinson"),
    
  679.             ("surface", 123),
    
  680.             ("case when name='Angus & Robinson' then chain else name end", "Westfield"),
    
  681.         )
    
  682.         for sql, expected_result in tests:
    
  683.             with self.subTest(sql=sql):
    
  684.                 self.assertSequenceEqual(
    
  685.                     DepartmentStore.objects.annotate(
    
  686.                         annotation=RawSQL(sql, ()),
    
  687.                     ).values_list("annotation", flat=True),
    
  688.                     [expected_result],
    
  689.                 )
    
  690. 
    
  691.     def test_annotate_exists(self):
    
  692.         authors = Author.objects.annotate(c=Count("id")).filter(c__gt=1)
    
  693.         self.assertFalse(authors.exists())
    
  694. 
    
  695.     def test_column_field_ordering(self):
    
  696.         """
    
  697.         Columns are aligned in the correct order for resolve_columns. This test
    
  698.         will fail on MySQL if column ordering is out. Column fields should be
    
  699.         aligned as:
    
  700.         1. extra_select
    
  701.         2. model_fields
    
  702.         3. annotation_fields
    
  703.         4. model_related_fields
    
  704.         """
    
  705.         store = Store.objects.first()
    
  706.         Employee.objects.create(
    
  707.             id=1,
    
  708.             first_name="Max",
    
  709.             manager=True,
    
  710.             last_name="Paine",
    
  711.             store=store,
    
  712.             age=23,
    
  713.             salary=Decimal(50000.00),
    
  714.         )
    
  715.         Employee.objects.create(
    
  716.             id=2,
    
  717.             first_name="Buffy",
    
  718.             manager=False,
    
  719.             last_name="Summers",
    
  720.             store=store,
    
  721.             age=18,
    
  722.             salary=Decimal(40000.00),
    
  723.         )
    
  724. 
    
  725.         qs = (
    
  726.             Employee.objects.extra(select={"random_value": "42"})
    
  727.             .select_related("store")
    
  728.             .annotate(
    
  729.                 annotated_value=Value(17),
    
  730.             )
    
  731.         )
    
  732. 
    
  733.         rows = [
    
  734.             (1, "Max", True, 42, "Paine", 23, Decimal(50000.00), store.name, 17),
    
  735.             (2, "Buffy", False, 42, "Summers", 18, Decimal(40000.00), store.name, 17),
    
  736.         ]
    
  737. 
    
  738.         self.assertQuerysetEqual(
    
  739.             qs.order_by("id"),
    
  740.             rows,
    
  741.             lambda e: (
    
  742.                 e.id,
    
  743.                 e.first_name,
    
  744.                 e.manager,
    
  745.                 e.random_value,
    
  746.                 e.last_name,
    
  747.                 e.age,
    
  748.                 e.salary,
    
  749.                 e.store.name,
    
  750.                 e.annotated_value,
    
  751.             ),
    
  752.         )
    
  753. 
    
  754.     def test_column_field_ordering_with_deferred(self):
    
  755.         store = Store.objects.first()
    
  756.         Employee.objects.create(
    
  757.             id=1,
    
  758.             first_name="Max",
    
  759.             manager=True,
    
  760.             last_name="Paine",
    
  761.             store=store,
    
  762.             age=23,
    
  763.             salary=Decimal(50000.00),
    
  764.         )
    
  765.         Employee.objects.create(
    
  766.             id=2,
    
  767.             first_name="Buffy",
    
  768.             manager=False,
    
  769.             last_name="Summers",
    
  770.             store=store,
    
  771.             age=18,
    
  772.             salary=Decimal(40000.00),
    
  773.         )
    
  774. 
    
  775.         qs = (
    
  776.             Employee.objects.extra(select={"random_value": "42"})
    
  777.             .select_related("store")
    
  778.             .annotate(
    
  779.                 annotated_value=Value(17),
    
  780.             )
    
  781.         )
    
  782. 
    
  783.         rows = [
    
  784.             (1, "Max", True, 42, "Paine", 23, Decimal(50000.00), store.name, 17),
    
  785.             (2, "Buffy", False, 42, "Summers", 18, Decimal(40000.00), store.name, 17),
    
  786.         ]
    
  787. 
    
  788.         # and we respect deferred columns!
    
  789.         self.assertQuerysetEqual(
    
  790.             qs.defer("age").order_by("id"),
    
  791.             rows,
    
  792.             lambda e: (
    
  793.                 e.id,
    
  794.                 e.first_name,
    
  795.                 e.manager,
    
  796.                 e.random_value,
    
  797.                 e.last_name,
    
  798.                 e.age,
    
  799.                 e.salary,
    
  800.                 e.store.name,
    
  801.                 e.annotated_value,
    
  802.             ),
    
  803.         )
    
  804. 
    
  805.     def test_custom_functions(self):
    
  806.         Company(
    
  807.             name="Apple",
    
  808.             motto=None,
    
  809.             ticker_name="APPL",
    
  810.             description="Beautiful Devices",
    
  811.         ).save()
    
  812.         Company(
    
  813.             name="Django Software Foundation",
    
  814.             motto=None,
    
  815.             ticker_name=None,
    
  816.             description=None,
    
  817.         ).save()
    
  818.         Company(
    
  819.             name="Google",
    
  820.             motto="Do No Evil",
    
  821.             ticker_name="GOOG",
    
  822.             description="Internet Company",
    
  823.         ).save()
    
  824.         Company(
    
  825.             name="Yahoo", motto=None, ticker_name=None, description="Internet Company"
    
  826.         ).save()
    
  827. 
    
  828.         qs = Company.objects.annotate(
    
  829.             tagline=Func(
    
  830.                 F("motto"),
    
  831.                 F("ticker_name"),
    
  832.                 F("description"),
    
  833.                 Value("No Tag"),
    
  834.                 function="COALESCE",
    
  835.             )
    
  836.         ).order_by("name")
    
  837. 
    
  838.         self.assertQuerysetEqual(
    
  839.             qs,
    
  840.             [
    
  841.                 ("Apple", "APPL"),
    
  842.                 ("Django Software Foundation", "No Tag"),
    
  843.                 ("Google", "Do No Evil"),
    
  844.                 ("Yahoo", "Internet Company"),
    
  845.             ],
    
  846.             lambda c: (c.name, c.tagline),
    
  847.         )
    
  848. 
    
  849.     def test_custom_functions_can_ref_other_functions(self):
    
  850.         Company(
    
  851.             name="Apple",
    
  852.             motto=None,
    
  853.             ticker_name="APPL",
    
  854.             description="Beautiful Devices",
    
  855.         ).save()
    
  856.         Company(
    
  857.             name="Django Software Foundation",
    
  858.             motto=None,
    
  859.             ticker_name=None,
    
  860.             description=None,
    
  861.         ).save()
    
  862.         Company(
    
  863.             name="Google",
    
  864.             motto="Do No Evil",
    
  865.             ticker_name="GOOG",
    
  866.             description="Internet Company",
    
  867.         ).save()
    
  868.         Company(
    
  869.             name="Yahoo", motto=None, ticker_name=None, description="Internet Company"
    
  870.         ).save()
    
  871. 
    
  872.         class Lower(Func):
    
  873.             function = "LOWER"
    
  874. 
    
  875.         qs = (
    
  876.             Company.objects.annotate(
    
  877.                 tagline=Func(
    
  878.                     F("motto"),
    
  879.                     F("ticker_name"),
    
  880.                     F("description"),
    
  881.                     Value("No Tag"),
    
  882.                     function="COALESCE",
    
  883.                 )
    
  884.             )
    
  885.             .annotate(
    
  886.                 tagline_lower=Lower(F("tagline")),
    
  887.             )
    
  888.             .order_by("name")
    
  889.         )
    
  890. 
    
  891.         # LOWER function supported by:
    
  892.         # oracle, postgres, mysql, sqlite, sqlserver
    
  893. 
    
  894.         self.assertQuerysetEqual(
    
  895.             qs,
    
  896.             [
    
  897.                 ("Apple", "APPL".lower()),
    
  898.                 ("Django Software Foundation", "No Tag".lower()),
    
  899.                 ("Google", "Do No Evil".lower()),
    
  900.                 ("Yahoo", "Internet Company".lower()),
    
  901.             ],
    
  902.             lambda c: (c.name, c.tagline_lower),
    
  903.         )
    
  904. 
    
  905.     def test_boolean_value_annotation(self):
    
  906.         books = Book.objects.annotate(
    
  907.             is_book=Value(True, output_field=BooleanField()),
    
  908.             is_pony=Value(False, output_field=BooleanField()),
    
  909.             is_none=Value(None, output_field=BooleanField(null=True)),
    
  910.         )
    
  911.         self.assertGreater(len(books), 0)
    
  912.         for book in books:
    
  913.             self.assertIs(book.is_book, True)
    
  914.             self.assertIs(book.is_pony, False)
    
  915.             self.assertIsNone(book.is_none)
    
  916. 
    
  917.     def test_annotation_in_f_grouped_by_annotation(self):
    
  918.         qs = (
    
  919.             Publisher.objects.annotate(multiplier=Value(3))
    
  920.             # group by option => sum of value * multiplier
    
  921.             .values("name")
    
  922.             .annotate(multiplied_value_sum=Sum(F("multiplier") * F("num_awards")))
    
  923.             .order_by()
    
  924.         )
    
  925.         self.assertCountEqual(
    
  926.             qs,
    
  927.             [
    
  928.                 {"multiplied_value_sum": 9, "name": "Apress"},
    
  929.                 {"multiplied_value_sum": 0, "name": "Jonno's House of Books"},
    
  930.                 {"multiplied_value_sum": 27, "name": "Morgan Kaufmann"},
    
  931.                 {"multiplied_value_sum": 21, "name": "Prentice Hall"},
    
  932.                 {"multiplied_value_sum": 3, "name": "Sams"},
    
  933.             ],
    
  934.         )
    
  935. 
    
  936.     def test_arguments_must_be_expressions(self):
    
  937.         msg = "QuerySet.annotate() received non-expression(s): %s."
    
  938.         with self.assertRaisesMessage(TypeError, msg % BooleanField()):
    
  939.             Book.objects.annotate(BooleanField())
    
  940.         with self.assertRaisesMessage(TypeError, msg % True):
    
  941.             Book.objects.annotate(is_book=True)
    
  942.         with self.assertRaisesMessage(
    
  943.             TypeError, msg % ", ".join([str(BooleanField()), "True"])
    
  944.         ):
    
  945.             Book.objects.annotate(BooleanField(), Value(False), is_book=True)
    
  946. 
    
  947.     def test_chaining_annotation_filter_with_m2m(self):
    
  948.         qs = (
    
  949.             Author.objects.filter(
    
  950.                 name="Adrian Holovaty",
    
  951.                 friends__age=35,
    
  952.             )
    
  953.             .annotate(
    
  954.                 jacob_name=F("friends__name"),
    
  955.             )
    
  956.             .filter(
    
  957.                 friends__age=29,
    
  958.             )
    
  959.             .annotate(
    
  960.                 james_name=F("friends__name"),
    
  961.             )
    
  962.             .values("jacob_name", "james_name")
    
  963.         )
    
  964.         self.assertCountEqual(
    
  965.             qs,
    
  966.             [{"jacob_name": "Jacob Kaplan-Moss", "james_name": "James Bennett"}],
    
  967.         )
    
  968. 
    
  969.     def test_annotation_filter_with_subquery(self):
    
  970.         long_books_qs = (
    
  971.             Book.objects.filter(
    
  972.                 publisher=OuterRef("pk"),
    
  973.                 pages__gt=400,
    
  974.             )
    
  975.             .values("publisher")
    
  976.             .annotate(count=Count("pk"))
    
  977.             .values("count")
    
  978.         )
    
  979.         publisher_books_qs = (
    
  980.             Publisher.objects.annotate(
    
  981.                 total_books=Count("book"),
    
  982.             )
    
  983.             .filter(
    
  984.                 total_books=Subquery(long_books_qs, output_field=IntegerField()),
    
  985.             )
    
  986.             .values("name")
    
  987.         )
    
  988.         self.assertCountEqual(
    
  989.             publisher_books_qs, [{"name": "Sams"}, {"name": "Morgan Kaufmann"}]
    
  990.         )
    
  991. 
    
  992.     def test_annotation_exists_aggregate_values_chaining(self):
    
  993.         qs = (
    
  994.             Book.objects.values("publisher")
    
  995.             .annotate(
    
  996.                 has_authors=Exists(
    
  997.                     Book.authors.through.objects.filter(book=OuterRef("pk"))
    
  998.                 ),
    
  999.                 max_pubdate=Max("pubdate"),
    
  1000.             )
    
  1001.             .values_list("max_pubdate", flat=True)
    
  1002.             .order_by("max_pubdate")
    
  1003.         )
    
  1004.         self.assertCountEqual(
    
  1005.             qs,
    
  1006.             [
    
  1007.                 datetime.date(1991, 10, 15),
    
  1008.                 datetime.date(2008, 3, 3),
    
  1009.                 datetime.date(2008, 6, 23),
    
  1010.                 datetime.date(2008, 11, 3),
    
  1011.             ],
    
  1012.         )
    
  1013. 
    
  1014.     @skipUnlessDBFeature("supports_subqueries_in_group_by")
    
  1015.     def test_annotation_subquery_and_aggregate_values_chaining(self):
    
  1016.         qs = (
    
  1017.             Book.objects.annotate(pub_year=ExtractYear("pubdate"))
    
  1018.             .values("pub_year")
    
  1019.             .annotate(
    
  1020.                 top_rating=Subquery(
    
  1021.                     Book.objects.filter(pubdate__year=OuterRef("pub_year"))
    
  1022.                     .order_by("-rating")
    
  1023.                     .values("rating")[:1]
    
  1024.                 ),
    
  1025.                 total_pages=Sum("pages"),
    
  1026.             )
    
  1027.             .values("pub_year", "total_pages", "top_rating")
    
  1028.         )
    
  1029.         self.assertCountEqual(
    
  1030.             qs,
    
  1031.             [
    
  1032.                 {"pub_year": 1991, "top_rating": 5.0, "total_pages": 946},
    
  1033.                 {"pub_year": 1995, "top_rating": 4.0, "total_pages": 1132},
    
  1034.                 {"pub_year": 2007, "top_rating": 4.5, "total_pages": 447},
    
  1035.                 {"pub_year": 2008, "top_rating": 4.0, "total_pages": 1178},
    
  1036.             ],
    
  1037.         )
    
  1038. 
    
  1039.     def test_annotation_subquery_outerref_transform(self):
    
  1040.         qs = Book.objects.annotate(
    
  1041.             top_rating_year=Subquery(
    
  1042.                 Book.objects.filter(pubdate__year=OuterRef("pubdate__year"))
    
  1043.                 .order_by("-rating")
    
  1044.                 .values("rating")[:1]
    
  1045.             ),
    
  1046.         ).values("pubdate__year", "top_rating_year")
    
  1047.         self.assertCountEqual(
    
  1048.             qs,
    
  1049.             [
    
  1050.                 {"pubdate__year": 1991, "top_rating_year": 5.0},
    
  1051.                 {"pubdate__year": 1995, "top_rating_year": 4.0},
    
  1052.                 {"pubdate__year": 2007, "top_rating_year": 4.5},
    
  1053.                 {"pubdate__year": 2008, "top_rating_year": 4.0},
    
  1054.                 {"pubdate__year": 2008, "top_rating_year": 4.0},
    
  1055.                 {"pubdate__year": 2008, "top_rating_year": 4.0},
    
  1056.             ],
    
  1057.         )
    
  1058. 
    
  1059.     def test_annotation_aggregate_with_m2o(self):
    
  1060.         qs = (
    
  1061.             Author.objects.filter(age__lt=30)
    
  1062.             .annotate(
    
  1063.                 max_pages=Case(
    
  1064.                     When(book_contact_set__isnull=True, then=Value(0)),
    
  1065.                     default=Max(F("book__pages")),
    
  1066.                 ),
    
  1067.             )
    
  1068.             .values("name", "max_pages")
    
  1069.         )
    
  1070.         self.assertCountEqual(
    
  1071.             qs,
    
  1072.             [
    
  1073.                 {"name": "James Bennett", "max_pages": 300},
    
  1074.                 {"name": "Paul Bissex", "max_pages": 0},
    
  1075.                 {"name": "Wesley J. Chun", "max_pages": 0},
    
  1076.             ],
    
  1077.         )
    
  1078. 
    
  1079.     def test_alias_sql_injection(self):
    
  1080.         crafted_alias = """injected_name" from "annotations_book"; --"""
    
  1081.         msg = (
    
  1082.             "Column aliases cannot contain whitespace characters, quotation marks, "
    
  1083.             "semicolons, or SQL comments."
    
  1084.         )
    
  1085.         with self.assertRaisesMessage(ValueError, msg):
    
  1086.             Book.objects.annotate(**{crafted_alias: Value(1)})
    
  1087. 
    
  1088.     def test_alias_forbidden_chars(self):
    
  1089.         tests = [
    
  1090.             'al"ias',
    
  1091.             "a'lias",
    
  1092.             "ali`as",
    
  1093.             "alia s",
    
  1094.             "alias\t",
    
  1095.             "ali\nas",
    
  1096.             "alias--",
    
  1097.             "ali/*as",
    
  1098.             "alias*/",
    
  1099.             "alias;",
    
  1100.             # [] are used by MSSQL.
    
  1101.             "alias[",
    
  1102.             "alias]",
    
  1103.         ]
    
  1104.         msg = (
    
  1105.             "Column aliases cannot contain whitespace characters, quotation marks, "
    
  1106.             "semicolons, or SQL comments."
    
  1107.         )
    
  1108.         for crafted_alias in tests:
    
  1109.             with self.subTest(crafted_alias):
    
  1110.                 with self.assertRaisesMessage(ValueError, msg):
    
  1111.                     Book.objects.annotate(**{crafted_alias: Value(1)})
    
  1112. 
    
  1113. 
    
  1114. class AliasTests(TestCase):
    
  1115.     @classmethod
    
  1116.     def setUpTestData(cls):
    
  1117.         cls.a1 = Author.objects.create(name="Adrian Holovaty", age=34)
    
  1118.         cls.a2 = Author.objects.create(name="Jacob Kaplan-Moss", age=35)
    
  1119.         cls.a3 = Author.objects.create(name="James Bennett", age=34)
    
  1120.         cls.a4 = Author.objects.create(name="Peter Norvig", age=57)
    
  1121.         cls.a5 = Author.objects.create(name="Stuart Russell", age=46)
    
  1122.         p1 = Publisher.objects.create(name="Apress", num_awards=3)
    
  1123. 
    
  1124.         cls.b1 = Book.objects.create(
    
  1125.             isbn="159059725",
    
  1126.             pages=447,
    
  1127.             rating=4.5,
    
  1128.             price=Decimal("30.00"),
    
  1129.             contact=cls.a1,
    
  1130.             publisher=p1,
    
  1131.             pubdate=datetime.date(2007, 12, 6),
    
  1132.             name="The Definitive Guide to Django: Web Development Done Right",
    
  1133.         )
    
  1134.         cls.b2 = Book.objects.create(
    
  1135.             isbn="159059996",
    
  1136.             pages=300,
    
  1137.             rating=4.0,
    
  1138.             price=Decimal("29.69"),
    
  1139.             contact=cls.a3,
    
  1140.             publisher=p1,
    
  1141.             pubdate=datetime.date(2008, 6, 23),
    
  1142.             name="Practical Django Projects",
    
  1143.         )
    
  1144.         cls.b3 = Book.objects.create(
    
  1145.             isbn="013790395",
    
  1146.             pages=1132,
    
  1147.             rating=4.0,
    
  1148.             price=Decimal("82.80"),
    
  1149.             contact=cls.a4,
    
  1150.             publisher=p1,
    
  1151.             pubdate=datetime.date(1995, 1, 15),
    
  1152.             name="Artificial Intelligence: A Modern Approach",
    
  1153.         )
    
  1154.         cls.b4 = Book.objects.create(
    
  1155.             isbn="155860191",
    
  1156.             pages=946,
    
  1157.             rating=5.0,
    
  1158.             price=Decimal("75.00"),
    
  1159.             contact=cls.a4,
    
  1160.             publisher=p1,
    
  1161.             pubdate=datetime.date(1991, 10, 15),
    
  1162.             name=(
    
  1163.                 "Paradigms of Artificial Intelligence Programming: Case Studies in "
    
  1164.                 "Common Lisp"
    
  1165.             ),
    
  1166.         )
    
  1167.         cls.b1.authors.add(cls.a1, cls.a2)
    
  1168.         cls.b2.authors.add(cls.a3)
    
  1169.         cls.b3.authors.add(cls.a4, cls.a5)
    
  1170.         cls.b4.authors.add(cls.a4)
    
  1171. 
    
  1172.         Store.objects.create(
    
  1173.             name="Amazon.com",
    
  1174.             original_opening=datetime.datetime(1994, 4, 23, 9, 17, 42),
    
  1175.             friday_night_closing=datetime.time(23, 59, 59),
    
  1176.         )
    
  1177.         Store.objects.create(
    
  1178.             name="Books.com",
    
  1179.             original_opening=datetime.datetime(2001, 3, 15, 11, 23, 37),
    
  1180.             friday_night_closing=datetime.time(23, 59, 59),
    
  1181.         )
    
  1182. 
    
  1183.     def test_basic_alias(self):
    
  1184.         qs = Book.objects.alias(is_book=Value(1))
    
  1185.         self.assertIs(hasattr(qs.first(), "is_book"), False)
    
  1186. 
    
  1187.     def test_basic_alias_annotation(self):
    
  1188.         qs = Book.objects.alias(
    
  1189.             is_book_alias=Value(1),
    
  1190.         ).annotate(is_book=F("is_book_alias"))
    
  1191.         self.assertIs(hasattr(qs.first(), "is_book_alias"), False)
    
  1192.         for book in qs:
    
  1193.             with self.subTest(book=book):
    
  1194.                 self.assertEqual(book.is_book, 1)
    
  1195. 
    
  1196.     def test_basic_alias_f_annotation(self):
    
  1197.         qs = Book.objects.alias(another_rating_alias=F("rating")).annotate(
    
  1198.             another_rating=F("another_rating_alias")
    
  1199.         )
    
  1200.         self.assertIs(hasattr(qs.first(), "another_rating_alias"), False)
    
  1201.         for book in qs:
    
  1202.             with self.subTest(book=book):
    
  1203.                 self.assertEqual(book.another_rating, book.rating)
    
  1204. 
    
  1205.     def test_basic_alias_f_transform_annotation(self):
    
  1206.         qs = Book.objects.alias(
    
  1207.             pubdate_alias=F("pubdate"),
    
  1208.         ).annotate(pubdate_year=F("pubdate_alias__year"))
    
  1209.         self.assertIs(hasattr(qs.first(), "pubdate_alias"), False)
    
  1210.         for book in qs:
    
  1211.             with self.subTest(book=book):
    
  1212.                 self.assertEqual(book.pubdate_year, book.pubdate.year)
    
  1213. 
    
  1214.     def test_alias_after_annotation(self):
    
  1215.         qs = Book.objects.annotate(
    
  1216.             is_book=Value(1),
    
  1217.         ).alias(is_book_alias=F("is_book"))
    
  1218.         book = qs.first()
    
  1219.         self.assertIs(hasattr(book, "is_book"), True)
    
  1220.         self.assertIs(hasattr(book, "is_book_alias"), False)
    
  1221. 
    
  1222.     def test_overwrite_annotation_with_alias(self):
    
  1223.         qs = Book.objects.annotate(is_book=Value(1)).alias(is_book=F("is_book"))
    
  1224.         self.assertIs(hasattr(qs.first(), "is_book"), False)
    
  1225. 
    
  1226.     def test_overwrite_alias_with_annotation(self):
    
  1227.         qs = Book.objects.alias(is_book=Value(1)).annotate(is_book=F("is_book"))
    
  1228.         for book in qs:
    
  1229.             with self.subTest(book=book):
    
  1230.                 self.assertEqual(book.is_book, 1)
    
  1231. 
    
  1232.     def test_alias_annotation_expression(self):
    
  1233.         qs = Book.objects.alias(
    
  1234.             is_book_alias=Value(1),
    
  1235.         ).annotate(is_book=Coalesce("is_book_alias", 0))
    
  1236.         self.assertIs(hasattr(qs.first(), "is_book_alias"), False)
    
  1237.         for book in qs:
    
  1238.             with self.subTest(book=book):
    
  1239.                 self.assertEqual(book.is_book, 1)
    
  1240. 
    
  1241.     def test_alias_default_alias_expression(self):
    
  1242.         qs = Author.objects.alias(
    
  1243.             Sum("book__pages"),
    
  1244.         ).filter(book__pages__sum__gt=2000)
    
  1245.         self.assertIs(hasattr(qs.first(), "book__pages__sum"), False)
    
  1246.         self.assertSequenceEqual(qs, [self.a4])
    
  1247. 
    
  1248.     def test_joined_alias_annotation(self):
    
  1249.         qs = (
    
  1250.             Book.objects.select_related("publisher")
    
  1251.             .alias(
    
  1252.                 num_awards_alias=F("publisher__num_awards"),
    
  1253.             )
    
  1254.             .annotate(num_awards=F("num_awards_alias"))
    
  1255.         )
    
  1256.         self.assertIs(hasattr(qs.first(), "num_awards_alias"), False)
    
  1257.         for book in qs:
    
  1258.             with self.subTest(book=book):
    
  1259.                 self.assertEqual(book.num_awards, book.publisher.num_awards)
    
  1260. 
    
  1261.     def test_alias_annotate_with_aggregation(self):
    
  1262.         qs = Book.objects.alias(
    
  1263.             is_book_alias=Value(1),
    
  1264.             rating_count_alias=Count("rating"),
    
  1265.         ).annotate(
    
  1266.             is_book=F("is_book_alias"),
    
  1267.             rating_count=F("rating_count_alias"),
    
  1268.         )
    
  1269.         book = qs.first()
    
  1270.         self.assertIs(hasattr(book, "is_book_alias"), False)
    
  1271.         self.assertIs(hasattr(book, "rating_count_alias"), False)
    
  1272.         for book in qs:
    
  1273.             with self.subTest(book=book):
    
  1274.                 self.assertEqual(book.is_book, 1)
    
  1275.                 self.assertEqual(book.rating_count, 1)
    
  1276. 
    
  1277.     def test_filter_alias_with_f(self):
    
  1278.         qs = Book.objects.alias(
    
  1279.             other_rating=F("rating"),
    
  1280.         ).filter(other_rating=4.5)
    
  1281.         self.assertIs(hasattr(qs.first(), "other_rating"), False)
    
  1282.         self.assertSequenceEqual(qs, [self.b1])
    
  1283. 
    
  1284.     def test_filter_alias_with_double_f(self):
    
  1285.         qs = Book.objects.alias(
    
  1286.             other_rating=F("rating"),
    
  1287.         ).filter(other_rating=F("rating"))
    
  1288.         self.assertIs(hasattr(qs.first(), "other_rating"), False)
    
  1289.         self.assertEqual(qs.count(), Book.objects.count())
    
  1290. 
    
  1291.     def test_filter_alias_agg_with_double_f(self):
    
  1292.         qs = Book.objects.alias(
    
  1293.             sum_rating=Sum("rating"),
    
  1294.         ).filter(sum_rating=F("sum_rating"))
    
  1295.         self.assertIs(hasattr(qs.first(), "sum_rating"), False)
    
  1296.         self.assertEqual(qs.count(), Book.objects.count())
    
  1297. 
    
  1298.     def test_update_with_alias(self):
    
  1299.         Book.objects.alias(
    
  1300.             other_rating=F("rating") - 1,
    
  1301.         ).update(rating=F("other_rating"))
    
  1302.         self.b1.refresh_from_db()
    
  1303.         self.assertEqual(self.b1.rating, 3.5)
    
  1304. 
    
  1305.     def test_order_by_alias(self):
    
  1306.         qs = Author.objects.alias(other_age=F("age")).order_by("other_age")
    
  1307.         self.assertIs(hasattr(qs.first(), "other_age"), False)
    
  1308.         self.assertQuerysetEqual(qs, [34, 34, 35, 46, 57], lambda a: a.age)
    
  1309. 
    
  1310.     def test_order_by_alias_aggregate(self):
    
  1311.         qs = (
    
  1312.             Author.objects.values("age")
    
  1313.             .alias(age_count=Count("age"))
    
  1314.             .order_by("age_count", "age")
    
  1315.         )
    
  1316.         self.assertIs(hasattr(qs.first(), "age_count"), False)
    
  1317.         self.assertQuerysetEqual(qs, [35, 46, 57, 34], lambda a: a["age"])
    
  1318. 
    
  1319.     def test_dates_alias(self):
    
  1320.         qs = Book.objects.alias(
    
  1321.             pubdate_alias=F("pubdate"),
    
  1322.         ).dates("pubdate_alias", "month")
    
  1323.         self.assertCountEqual(
    
  1324.             qs,
    
  1325.             [
    
  1326.                 datetime.date(1991, 10, 1),
    
  1327.                 datetime.date(1995, 1, 1),
    
  1328.                 datetime.date(2007, 12, 1),
    
  1329.                 datetime.date(2008, 6, 1),
    
  1330.             ],
    
  1331.         )
    
  1332. 
    
  1333.     def test_datetimes_alias(self):
    
  1334.         qs = Store.objects.alias(
    
  1335.             original_opening_alias=F("original_opening"),
    
  1336.         ).datetimes("original_opening_alias", "year")
    
  1337.         self.assertCountEqual(
    
  1338.             qs,
    
  1339.             [
    
  1340.                 datetime.datetime(1994, 1, 1),
    
  1341.                 datetime.datetime(2001, 1, 1),
    
  1342.             ],
    
  1343.         )
    
  1344. 
    
  1345.     def test_aggregate_alias(self):
    
  1346.         msg = (
    
  1347.             "Cannot aggregate over the 'other_age' alias. Use annotate() to promote it."
    
  1348.         )
    
  1349.         with self.assertRaisesMessage(FieldError, msg):
    
  1350.             Author.objects.alias(
    
  1351.                 other_age=F("age"),
    
  1352.             ).aggregate(otherage_sum=Sum("other_age"))
    
  1353. 
    
  1354.     def test_defer_only_alias(self):
    
  1355.         qs = Book.objects.alias(rating_alias=F("rating") - 1)
    
  1356.         msg = "Book has no field named 'rating_alias'"
    
  1357.         for operation in ["defer", "only"]:
    
  1358.             with self.subTest(operation=operation):
    
  1359.                 with self.assertRaisesMessage(FieldDoesNotExist, msg):
    
  1360.                     getattr(qs, operation)("rating_alias").first()
    
  1361. 
    
  1362.     @skipUnlessDBFeature("can_distinct_on_fields")
    
  1363.     def test_distinct_on_alias(self):
    
  1364.         qs = Book.objects.alias(rating_alias=F("rating") - 1)
    
  1365.         msg = "Cannot resolve keyword 'rating_alias' into field."
    
  1366.         with self.assertRaisesMessage(FieldError, msg):
    
  1367.             qs.distinct("rating_alias").first()
    
  1368. 
    
  1369.     def test_values_alias(self):
    
  1370.         qs = Book.objects.alias(rating_alias=F("rating") - 1)
    
  1371.         msg = "Cannot select the 'rating_alias' alias. Use annotate() to promote it."
    
  1372.         for operation in ["values", "values_list"]:
    
  1373.             with self.subTest(operation=operation):
    
  1374.                 with self.assertRaisesMessage(FieldError, msg):
    
  1375.                     getattr(qs, operation)("rating_alias")
    
  1376. 
    
  1377.     def test_alias_sql_injection(self):
    
  1378.         crafted_alias = """injected_name" from "annotations_book"; --"""
    
  1379.         msg = (
    
  1380.             "Column aliases cannot contain whitespace characters, quotation marks, "
    
  1381.             "semicolons, or SQL comments."
    
  1382.         )
    
  1383.         with self.assertRaisesMessage(ValueError, msg):
    
  1384.             Book.objects.alias(**{crafted_alias: Value(1)})