mirror of
https://github.com/django/django.git
synced 2024-12-22 09:05:43 +00:00
Fixed #34421 -- Fixed QuerySet.update() on querysets in descending order by annotations.
This commit is contained in:
parent
d2b688b966
commit
2ffa815c73
@ -108,6 +108,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
|||||||
"update.tests.AdvancedTests."
|
"update.tests.AdvancedTests."
|
||||||
"test_update_ordered_by_inline_m2m_annotation",
|
"test_update_ordered_by_inline_m2m_annotation",
|
||||||
"update.tests.AdvancedTests.test_update_ordered_by_m2m_annotation",
|
"update.tests.AdvancedTests.test_update_ordered_by_m2m_annotation",
|
||||||
|
"update.tests.AdvancedTests.test_update_ordered_by_m2m_annotation_desc",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if self.connection.mysql_is_mariadb and (
|
if self.connection.mysql_is_mariadb and (
|
||||||
|
@ -1190,11 +1190,18 @@ class QuerySet(AltersData):
|
|||||||
# Inline annotations in order_by(), if possible.
|
# Inline annotations in order_by(), if possible.
|
||||||
new_order_by = []
|
new_order_by = []
|
||||||
for col in query.order_by:
|
for col in query.order_by:
|
||||||
if annotation := query.annotations.get(col):
|
alias = col
|
||||||
|
descending = False
|
||||||
|
if isinstance(alias, str) and alias.startswith("-"):
|
||||||
|
alias = alias.removeprefix("-")
|
||||||
|
descending = True
|
||||||
|
if annotation := query.annotations.get(alias):
|
||||||
if getattr(annotation, "contains_aggregate", False):
|
if getattr(annotation, "contains_aggregate", False):
|
||||||
raise exceptions.FieldError(
|
raise exceptions.FieldError(
|
||||||
f"Cannot update when ordering by an aggregate: {annotation}"
|
f"Cannot update when ordering by an aggregate: {annotation}"
|
||||||
)
|
)
|
||||||
|
if descending:
|
||||||
|
annotation = annotation.desc()
|
||||||
new_order_by.append(annotation)
|
new_order_by.append(annotation)
|
||||||
else:
|
else:
|
||||||
new_order_by.append(col)
|
new_order_by.append(col)
|
||||||
|
@ -249,6 +249,13 @@ class AdvancedTests(TestCase):
|
|||||||
Bar.objects.annotate(abs_id=Abs("m2m_foo")).order_by("abs_id").update(x=3)
|
Bar.objects.annotate(abs_id=Abs("m2m_foo")).order_by("abs_id").update(x=3)
|
||||||
self.assertEqual(Bar.objects.get().x, 3)
|
self.assertEqual(Bar.objects.get().x, 3)
|
||||||
|
|
||||||
|
def test_update_ordered_by_m2m_annotation_desc(self):
|
||||||
|
foo = Foo.objects.create(target="test")
|
||||||
|
Bar.objects.create(foo=foo)
|
||||||
|
|
||||||
|
Bar.objects.annotate(abs_id=Abs("m2m_foo")).order_by("-abs_id").update(x=4)
|
||||||
|
self.assertEqual(Bar.objects.get().x, 4)
|
||||||
|
|
||||||
def test_update_negated_f(self):
|
def test_update_negated_f(self):
|
||||||
DataPoint.objects.update(is_active=~F("is_active"))
|
DataPoint.objects.update(is_active=~F("is_active"))
|
||||||
self.assertCountEqual(
|
self.assertCountEqual(
|
||||||
@ -309,6 +316,14 @@ class MySQLUpdateOrderByTest(TestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(updated, 2)
|
self.assertEqual(updated, 2)
|
||||||
|
|
||||||
|
def test_order_by_update_on_unique_constraint_annotation_desc(self):
|
||||||
|
updated = (
|
||||||
|
UniqueNumber.objects.annotate(number_annotation=F("number"))
|
||||||
|
.order_by("-number_annotation")
|
||||||
|
.update(number=F("number") + 1)
|
||||||
|
)
|
||||||
|
self.assertEqual(updated, 2)
|
||||||
|
|
||||||
def test_order_by_update_on_parent_unique_constraint(self):
|
def test_order_by_update_on_parent_unique_constraint(self):
|
||||||
# Ordering by inherited fields is omitted because joined fields cannot
|
# Ordering by inherited fields is omitted because joined fields cannot
|
||||||
# be used in the ORDER BY clause.
|
# be used in the ORDER BY clause.
|
||||||
|
Loading…
Reference in New Issue
Block a user