1. from django.db.models import F, Sum
    
  2. from django.test import TestCase
    
  3. 
    
  4. from .models import Company, Employee
    
  5. 
    
  6. 
    
  7. class ValuesExpressionsTests(TestCase):
    
  8.     @classmethod
    
  9.     def setUpTestData(cls):
    
  10.         Company.objects.create(
    
  11.             name="Example Inc.",
    
  12.             num_employees=2300,
    
  13.             num_chairs=5,
    
  14.             ceo=Employee.objects.create(firstname="Joe", lastname="Smith", salary=10),
    
  15.         )
    
  16.         Company.objects.create(
    
  17.             name="Foobar Ltd.",
    
  18.             num_employees=3,
    
  19.             num_chairs=4,
    
  20.             ceo=Employee.objects.create(firstname="Frank", lastname="Meyer", salary=20),
    
  21.         )
    
  22.         Company.objects.create(
    
  23.             name="Test GmbH",
    
  24.             num_employees=32,
    
  25.             num_chairs=1,
    
  26.             ceo=Employee.objects.create(
    
  27.                 firstname="Max", lastname="Mustermann", salary=30
    
  28.             ),
    
  29.         )
    
  30. 
    
  31.     def test_values_expression(self):
    
  32.         self.assertSequenceEqual(
    
  33.             Company.objects.values(salary=F("ceo__salary")),
    
  34.             [{"salary": 10}, {"salary": 20}, {"salary": 30}],
    
  35.         )
    
  36. 
    
  37.     def test_values_expression_alias_sql_injection(self):
    
  38.         crafted_alias = """injected_name" from "expressions_company"; --"""
    
  39.         msg = (
    
  40.             "Column aliases cannot contain whitespace characters, quotation marks, "
    
  41.             "semicolons, or SQL comments."
    
  42.         )
    
  43.         with self.assertRaisesMessage(ValueError, msg):
    
  44.             Company.objects.values(**{crafted_alias: F("ceo__salary")})
    
  45. 
    
  46.     def test_values_expression_group_by(self):
    
  47.         # values() applies annotate() first, so values selected are grouped by
    
  48.         # id, not firstname.
    
  49.         Employee.objects.create(firstname="Joe", lastname="Jones", salary=2)
    
  50.         joes = Employee.objects.filter(firstname="Joe")
    
  51.         self.assertSequenceEqual(
    
  52.             joes.values("firstname", sum_salary=Sum("salary")).order_by("sum_salary"),
    
  53.             [
    
  54.                 {"firstname": "Joe", "sum_salary": 2},
    
  55.                 {"firstname": "Joe", "sum_salary": 10},
    
  56.             ],
    
  57.         )
    
  58.         self.assertSequenceEqual(
    
  59.             joes.values("firstname").annotate(sum_salary=Sum("salary")),
    
  60.             [{"firstname": "Joe", "sum_salary": 12}],
    
  61.         )
    
  62. 
    
  63.     def test_chained_values_with_expression(self):
    
  64.         Employee.objects.create(firstname="Joe", lastname="Jones", salary=2)
    
  65.         joes = Employee.objects.filter(firstname="Joe").values("firstname")
    
  66.         self.assertSequenceEqual(
    
  67.             joes.values("firstname", sum_salary=Sum("salary")),
    
  68.             [{"firstname": "Joe", "sum_salary": 12}],
    
  69.         )
    
  70.         self.assertSequenceEqual(
    
  71.             joes.values(sum_salary=Sum("salary")), [{"sum_salary": 12}]
    
  72.         )
    
  73. 
    
  74.     def test_values_list_expression(self):
    
  75.         companies = Company.objects.values_list("name", F("ceo__salary"))
    
  76.         self.assertCountEqual(
    
  77.             companies, [("Example Inc.", 10), ("Foobar Ltd.", 20), ("Test GmbH", 30)]
    
  78.         )
    
  79. 
    
  80.     def test_values_list_expression_flat(self):
    
  81.         companies = Company.objects.values_list(F("ceo__salary"), flat=True)
    
  82.         self.assertCountEqual(companies, (10, 20, 30))