[Django] #36122: Add sanity check against updating non-composite field with composite expression

9 views
Skip to first unread message

Django

unread,
Jan 21, 2025, 8:11:19 AMJan 21
to django-...@googlegroups.com
#36122: Add sanity check against updating non-composite field with composite
expression
-------------------------------------+-------------------------------------
Reporter: Jacob Walls | Type: Bug
Status: new | Component: Database
| layer (models, ORM)
Version: 5.2 | Severity: Release
| blocker
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Attempting to update a non-composite field via `.update()` with a
composite expression fails at the db level with an invalid query:

Rough test:
{{{#!diff
diff --git a/tests/composite_pk/test_update.py
b/tests/composite_pk/test_update.py
index ec770230fc..c5deac6d4b 100644
--- a/tests/composite_pk/test_update.py
+++ b/tests/composite_pk/test_update.py
@@ -1,4 +1,5 @@
from django.db import connection
+from django.db.models import F
from django.test import TestCase

from .models import Comment, Tenant, TimeStamped, Token, User
@@ -175,3 +176,9 @@ class CompositePKUpdateTests(TestCase):

with self.assertRaisesMessage(ValueError, msg):
Comment.objects.update(user=User())
+
+ def test_update_lhs_not_composite(self):
+ qs = Comment.objects.filter(user__email=self.user_1.email)
+ msg = "Composite expressions only work with composite fields."
+ with self.assertRaisesMessage(ValueError, msg):
+ qs.update(text=F("pk"))
}}}
----
{{{#!py
======================================================================
ERROR: test_update_lhs_not_composite
(composite_pk.test_update.CompositePKUpdateTests.test_update_lhs_not_composite)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/source/django/django/db/backends/utils.py", line 105, in
_execute
return self.cursor.execute(sql, params)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "/Users/source/django/django/db/backends/sqlite3/base.py", line
360, in execute
return super().execute(query, params)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
sqlite3.OperationalError: near ".": syntax error

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "/Users/source/django/tests/composite_pk/test_update.py", line 184,
in test_update_lhs_not_composite
qs.update(text=F("pk"))
~~~~~~~~~^^^^^^^^^^^^^^
File "/Users/source/django/django/db/models/query.py", line 1254, in
update
rows = query.get_compiler(self.db).execute_sql(ROW_COUNT)
File "/Users/source/django/django/db/models/sql/compiler.py", line 2068,
in execute_sql
row_count = super().execute_sql(result_type)
File "/Users/source/django/django/db/models/sql/compiler.py", line 1623,
in execute_sql
cursor.execute(sql, params)
~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "/Users/source/django/django/db/backends/utils.py", line 122, in
execute
return super().execute(sql, params)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "/Users/source/django/django/db/backends/utils.py", line 79, in
execute
return self._execute_with_wrappers(
~~~~~~~~~~~~~~~~~~~~~~~~~~~^
sql, params, many=False, executor=self._execute
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "/Users/source/django/django/db/backends/utils.py", line 92, in
_execute_with_wrappers
return executor(sql, params, many, context)
File "/Users/source/django/django/db/backends/utils.py", line 100, in
_execute
with self.db.wrap_database_errors:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/source/django/django/db/utils.py", line 91, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/Users/source/django/django/db/backends/utils.py", line 105, in
_execute
return self.cursor.execute(sql, params)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "/Users/source/django/django/db/backends/sqlite3/base.py", line
360, in execute
return super().execute(query, params)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
django.db.utils.OperationalError: near ".": syntax error

----------------------------------------------------------------------
(0.000) UPDATE "composite_pk_comment"
SET "text" = "composite_pk_comment"."tenant_id",
"composite_pk_comment"."comment_id"
WHERE ("composite_pk_comment"."tenant_id",
"composite_pk_comment"."comment_id") IN
(SELECT U0."tenant_id" AS "tenant",
U0."comment_id" AS "id"
FROM "composite_pk_comment" U0
INNER JOIN "composite_pk_user" U1 ON (U0."tenant_id" = U1."tenant_id"
AND U0."user_id" = U1."id")
WHERE U1."email" = 'user...@example.com');
args=('user...@example.com',); alias=default

----------------------------------------------------------------------
Ran 1 test in 0.014s

FAILED (errors=1)
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/36122>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Jan 21, 2025, 8:20:35 AMJan 21
to django-...@googlegroups.com
#36122: Add sanity check against updating non-composite field with composite
expression
-------------------------------------+-------------------------------------
Reporter: Jacob Walls | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Release blocker | Resolution:
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Jacob Walls):

I guess depending on the fix for #36120 this may turn out to be a
duplicate (pardon the noise if so)
--
Ticket URL: <https://code.djangoproject.com/ticket/36122#comment:1>

Django

unread,
Jan 22, 2025, 3:03:28 AMJan 22
to django-...@googlegroups.com
#36122: Add sanity check against updating non-composite field with composite
expression
-------------------------------------+-------------------------------------
Reporter: Jacob Walls | Owner: (none)
Type: Bug | Status: new
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Release blocker | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Sarah Boyce):

* stage: Unreviewed => Accepted

Comment:

Thank you!
Better safe than sorry, we can always close the tickets together with the
same fix
--
Ticket URL: <https://code.djangoproject.com/ticket/36122#comment:2>

Django

unread,
Jan 25, 2025, 3:48:08 PMJan 25
to django-...@googlegroups.com
#36122: Add sanity check against updating non-composite field with composite
expression
-------------------------------------+-------------------------------------
Reporter: Jacob Walls | Owner: Simon
| Charette
Type: Bug | Status: assigned
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Release blocker | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Simon Charette):

* owner: (none) => Simon Charette
* status: new => assigned

Comment:

I'm going to assign this one to complement #36120 per
ticket:36120#comment:5
--
Ticket URL: <https://code.djangoproject.com/ticket/36122#comment:3>

Django

unread,
Jan 25, 2025, 7:19:48 PMJan 25
to django-...@googlegroups.com
#36122: Add sanity check against updating non-composite field with composite
expression
-------------------------------------+-------------------------------------
Reporter: Jacob Walls | Owner: Simon
| Charette
Type: Bug | Status: assigned
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Release blocker | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Simon Charette):

* has_patch: 0 => 1

--
Ticket URL: <https://code.djangoproject.com/ticket/36122#comment:4>

Django

unread,
Jan 28, 2025, 5:13:19 AMJan 28
to django-...@googlegroups.com
#36122: Add sanity check against updating non-composite field with composite
expression
-------------------------------------+-------------------------------------
Reporter: Jacob Walls | Owner: Simon
| Charette
Type: Bug | Status: assigned
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Release blocker | Resolution:
Keywords: | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Sarah Boyce):

* stage: Accepted => Ready for checkin

--
Ticket URL: <https://code.djangoproject.com/ticket/36122#comment:5>

Django

unread,
Jan 28, 2025, 7:06:02 AMJan 28
to django-...@googlegroups.com
#36122: Add sanity check against updating non-composite field with composite
expression
-------------------------------------+-------------------------------------
Reporter: Jacob Walls | Owner: Simon
| Charette
Type: Bug | Status: closed
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Release blocker | Resolution: fixed
Keywords: | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Sarah Boyce <42296566+sarahboyce@…>):

* resolution: => fixed
* status: assigned => closed

Comment:

In [changeset:"efec74b90868c2e611f863bf4301d92ce08067e8" efec74b9]:
{{{#!CommitTicketReference repository=""
revision="efec74b90868c2e611f863bf4301d92ce08067e8"
Fixed #36122 -- Raised FieldError when updating with composite reference
value.

Thanks Jacob Walls for the report and test.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/36122#comment:6>

Django

unread,
Jan 28, 2025, 7:20:12 AMJan 28
to django-...@googlegroups.com
#36122: Add sanity check against updating non-composite field with composite
expression
-------------------------------------+-------------------------------------
Reporter: Jacob Walls | Owner: Simon
| Charette
Type: Bug | Status: closed
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Release blocker | Resolution: fixed
Keywords: | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Sarah Boyce <42296566+sarahboyce@…>):

In [changeset:"d4d2e09f19e5d764b8b4df34f048f8babf670e8e" d4d2e09]:
{{{#!CommitTicketReference repository=""
revision="d4d2e09f19e5d764b8b4df34f048f8babf670e8e"
[5.2.x] Fixed #36122 -- Raised FieldError when updating with composite
reference value.

Thanks Jacob Walls for the report and test.

Backport of efec74b90868c2e611f863bf4301d92ce08067e8 from main.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/36122#comment:7>
Reply all
Reply to author
Forward
0 new messages