test_queryset_values.py 3.1 KB

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