1
0
mirror of https://github.com/django/django.git synced 2025-10-23 21:59:11 +00:00

Fixed #25534, Fixed #31639 -- Added support for transform references in expressions.

Thanks Mariusz Felisiak and Simon Charette for reviews.
This commit is contained in:
Ian Foote
2020-11-15 22:43:47 +00:00
committed by Mariusz Felisiak
parent e46ca51c24
commit 8b040e3cbb
14 changed files with 354 additions and 82 deletions

View File

@@ -48,24 +48,35 @@ class WindowFunctionTests(TestCase):
])
def test_dense_rank(self):
qs = Employee.objects.annotate(rank=Window(
expression=DenseRank(),
order_by=ExtractYear(F('hire_date')).asc(),
))
self.assertQuerysetEqual(qs, [
('Jones', 45000, 'Accounting', datetime.date(2005, 11, 1), 1),
('Miller', 100000, 'Management', datetime.date(2005, 6, 1), 1),
('Johnson', 80000, 'Management', datetime.date(2005, 7, 1), 1),
('Smith', 55000, 'Sales', datetime.date(2007, 6, 1), 2),
('Jenson', 45000, 'Accounting', datetime.date(2008, 4, 1), 3),
('Smith', 38000, 'Marketing', datetime.date(2009, 10, 1), 4),
('Brown', 53000, 'Sales', datetime.date(2009, 9, 1), 4),
('Williams', 37000, 'Accounting', datetime.date(2009, 6, 1), 4),
('Wilkinson', 60000, 'IT', datetime.date(2011, 3, 1), 5),
('Johnson', 40000, 'Marketing', datetime.date(2012, 3, 1), 6),
('Moore', 34000, 'IT', datetime.date(2013, 8, 1), 7),
('Adams', 50000, 'Accounting', datetime.date(2013, 7, 1), 7),
], lambda entry: (entry.name, entry.salary, entry.department, entry.hire_date, entry.rank), ordered=False)
tests = [
ExtractYear(F('hire_date')).asc(),
F('hire_date__year').asc(),
]
for order_by in tests:
with self.subTest(order_by=order_by):
qs = Employee.objects.annotate(
rank=Window(expression=DenseRank(), order_by=order_by),
)
self.assertQuerysetEqual(qs, [
('Jones', 45000, 'Accounting', datetime.date(2005, 11, 1), 1),
('Miller', 100000, 'Management', datetime.date(2005, 6, 1), 1),
('Johnson', 80000, 'Management', datetime.date(2005, 7, 1), 1),
('Smith', 55000, 'Sales', datetime.date(2007, 6, 1), 2),
('Jenson', 45000, 'Accounting', datetime.date(2008, 4, 1), 3),
('Smith', 38000, 'Marketing', datetime.date(2009, 10, 1), 4),
('Brown', 53000, 'Sales', datetime.date(2009, 9, 1), 4),
('Williams', 37000, 'Accounting', datetime.date(2009, 6, 1), 4),
('Wilkinson', 60000, 'IT', datetime.date(2011, 3, 1), 5),
('Johnson', 40000, 'Marketing', datetime.date(2012, 3, 1), 6),
('Moore', 34000, 'IT', datetime.date(2013, 8, 1), 7),
('Adams', 50000, 'Accounting', datetime.date(2013, 7, 1), 7),
], lambda entry: (
entry.name,
entry.salary,
entry.department,
entry.hire_date,
entry.rank,
), ordered=False)
def test_department_salary(self):
qs = Employee.objects.annotate(department_sum=Window(
@@ -96,7 +107,7 @@ class WindowFunctionTests(TestCase):
"""
qs = Employee.objects.annotate(rank=Window(
expression=Rank(),
order_by=ExtractYear(F('hire_date')).asc(),
order_by=F('hire_date__year').asc(),
))
self.assertQuerysetEqual(qs, [
('Jones', 45000, 'Accounting', datetime.date(2005, 11, 1), 1),
@@ -523,7 +534,7 @@ class WindowFunctionTests(TestCase):
"""
qs = Employee.objects.annotate(max=Window(
expression=Max('salary'),
partition_by=[F('department'), ExtractYear(F('hire_date'))],
partition_by=[F('department'), F('hire_date__year')],
)).order_by('department', 'hire_date', 'name')
self.assertQuerysetEqual(qs, [
('Jones', 45000, 'Accounting', datetime.date(2005, 11, 1), 45000),
@@ -753,26 +764,32 @@ class WindowFunctionTests(TestCase):
Detail(value={'department': 'HR', 'name': 'Smith', 'salary': 55000}),
Detail(value={'department': 'PR', 'name': 'Moore', 'salary': 90000}),
])
qs = Detail.objects.annotate(department_sum=Window(
expression=Sum(Cast(
KeyTextTransform('salary', 'value'),
output_field=IntegerField(),
)),
partition_by=[KeyTransform('department', 'value')],
order_by=[KeyTransform('name', 'value')],
)).order_by('value__department', 'department_sum')
self.assertQuerysetEqual(qs, [
('Brown', 'HR', 50000, 50000),
('Smith', 'HR', 55000, 105000),
('Nowak', 'IT', 32000, 32000),
('Smith', 'IT', 37000, 69000),
('Moore', 'PR', 90000, 90000),
], lambda entry: (
entry.value['name'],
entry.value['department'],
entry.value['salary'],
entry.department_sum,
))
tests = [
(KeyTransform('department', 'value'), KeyTransform('name', 'value')),
(F('value__department'), F('value__name')),
]
for partition_by, order_by in tests:
with self.subTest(partition_by=partition_by, order_by=order_by):
qs = Detail.objects.annotate(department_sum=Window(
expression=Sum(Cast(
KeyTextTransform('salary', 'value'),
output_field=IntegerField(),
)),
partition_by=[partition_by],
order_by=[order_by],
)).order_by('value__department', 'department_sum')
self.assertQuerysetEqual(qs, [
('Brown', 'HR', 50000, 50000),
('Smith', 'HR', 55000, 105000),
('Nowak', 'IT', 32000, 32000),
('Smith', 'IT', 37000, 69000),
('Moore', 'PR', 90000, 90000),
], lambda entry: (
entry.value['name'],
entry.value['department'],
entry.value['salary'],
entry.department_sum,
))
def test_invalid_start_value_range(self):
msg = "start argument must be a negative integer, zero, or None, but got '3'."