[Django] #36034: ForeignKey to CompositePrimaryKey crashes.

8 views
Skip to first unread message

Django

unread,
Dec 22, 2024, 10:23:38 AM12/22/24
to django-...@googlegroups.com
#36034: ForeignKey to CompositePrimaryKey crashes.
-------------------------------------+-------------------------------------
Reporter: Mariusz | Owner: Mariusz Felisiak
Felisiak |
Type: Bug | Status: assigned
Component: Database | Version: dev
layer (models, ORM) |
Severity: Release | Keywords:
blocker |
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
I've created a sample project that tries to create a foreign key to the
table with `CompositePrimaryKey`:
{{{
class Release(models.Model):
pk = models.CompositePrimaryKey("version", "name")
version = models.IntegerField()
name = models.CharField(max_length=20)


class RefRelease(models.Model):
release = models.ForeignKey("Release", models.CASCADE)

}}}

It doesn't work (because #35956 is not implemented):

{{{
$ python manage.py sqlmigrate test_one 0001
BEGIN;
--
-- Create model Release
--
CREATE TABLE "test_one_release" ("version" integer NOT NULL, "name"
varchar(20) NOT NULL, PRIMARY KEY ("version", "name"));
--
-- Create model RefRelease
--
CREATE TABLE "test_one_refrelease" ("id" integer NOT NULL PRIMARY KEY
AUTOINCREMENT);
CREATE INDEX "test_one_refrelease_release_id_f24095be" ON
"test_one_refrelease" ("release_id");
COMMIT;
}}}

`FOREIGN KEY` has not been created in `"test_one_refrelease"`:

{{{
$ python manage.py dbshell
sqlite> pragma table_info(test_one_refrelease);
0|id|INTEGER|1||1
sqlite> pragma table_info(test_one_release);
0|version|INTEGER|1||1
1|name|varchar(20)|1||2
sqlite>
}}}

and any attempt to create a new object crashes:
{{{
$ python manage.py shell
>>> from test_one.models import *
>>> r = Release.objects.create(version=3, name="y")
>>> RefRelease.objects.create(release=r)
Traceback (most recent call last):
File "/django/django/db/backends/utils.py", line 105, in _execute
return self.cursor.execute(sql, params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/django/django/db/backends/sqlite3/base.py", line 360, in execute
return super().execute(query, params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
sqlite3.OperationalError: table test_one_refrelease has no column named
release_id

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

Traceback (most recent call last):
File "/django/django/db/backends/utils.py", line 134, in debug_sql
yield
File "/django/django/db/backends/utils.py", line 122, in execute
return super().execute(sql, params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/django/django/db/backends/utils.py", line 79, in execute
return self._execute_with_wrappers(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/django/django/db/backends/utils.py", line 92, in
_execute_with_wrappers
return executor(sql, params, many, context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/django/django/db/backends/utils.py", line 100, in _execute
with self.db.wrap_database_errors:
File "/django/django/db/utils.py", line 91, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/django/django/db/backends/utils.py", line 105, in _execute
return self.cursor.execute(sql, params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/django/django/db/backends/sqlite3/base.py", line 360, in execute
return super().execute(query, params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
django.db.utils.OperationalError: table test_one_refrelease has no column
named release_id

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/django/django/db/models/manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/django/django/db/models/query.py", line 663, in create
obj.save(force_insert=True, using=self.db)
File "/django/django/db/models/base.py", line 901, in save
self.save_base(
File "/django/django/db/models/base.py", line 1007, in save_base
updated = self._save_table(
^^^^^^^^^^^^^^^^^
File "/django/django/db/models/base.py", line 1170, in _save_table
results = self._do_insert(
^^^^^^^^^^^^^^^^
File "/django/django/db/models/base.py", line 1211, in _do_insert
return manager._insert(
^^^^^^^^^^^^^^^^
File "/django/django/db/models/manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/django/django/db/models/query.py", line 1849, in _insert
return query.get_compiler(using=using).execute_sql(returning_fields)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/django/django/db/models/sql/compiler.py", line 1891, in
execute_sql
cursor.execute(sql, params)
File "/django/django/db/backends/utils.py", line 121, in execute
with self.debug_sql(sql, params, use_last_executed_query=True):
File "/usr/local/lib/python3.12/contextlib.py", line 158, in __exit__
self.gen.throw(value)
File "/django/django/db/backends/utils.py", line 139, in debug_sql
sql = self.db.ops.last_executed_query(self.cursor, sql, params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/django/django/db/backends/sqlite3/operations.py", line 178, in
last_executed_query
params = self._quote_params_for_last_executed_query(params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/django/django/db/backends/sqlite3/operations.py", line 167, in
_quote_params_for_last_executed_query
return cursor.execute(sql, params).fetchone()
^^^^^^^^^^^^^^^^^^^^^^^^^^^
sqlite3.ProgrammingError: Error binding parameter 1: type 'tuple' is not
supported
}}}


IMO, we should at least raise an error (system check) in such cases. For
now, migrations are proceeding without any indication that anything went
wrong.
--
Ticket URL: <https://code.djangoproject.com/ticket/36034>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Dec 25, 2024, 11:49:43 AM12/25/24
to django-...@googlegroups.com
#36034: ForeignKey to CompositePrimaryKey crashes.
-------------------------------------+-------------------------------------
Reporter: Mariusz Felisiak | Owner: Mariusz
| Felisiak
Type: Bug | Status: assigned
Component: Database layer | Version: dev
(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 Tim Graham):

* stage: Unreviewed => Accepted

--
Ticket URL: <https://code.djangoproject.com/ticket/36034#comment:1>

Django

unread,
Jan 1, 2025, 11:59:36 AMJan 1
to django-...@googlegroups.com
#36034: ForeignKey to CompositePrimaryKey crashes.
-------------------------------------+-------------------------------------
Reporter: Mariusz Felisiak | Owner: Mariusz
| Felisiak
Type: Bug | Status: assigned
Component: Database layer | Version: dev
(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 Mariusz Felisiak):

* has_patch: 0 => 1

Comment:

[https://github.com/django/django/pull/18982 PR]
--
Ticket URL: <https://code.djangoproject.com/ticket/36034#comment:2>

Django

unread,
Jan 2, 2025, 5:14:15 AMJan 2
to django-...@googlegroups.com
#36034: ForeignKey to CompositePrimaryKey crashes.
-------------------------------------+-------------------------------------
Reporter: Mariusz Felisiak | Owner: Mariusz
| Felisiak
Type: Bug | Status: assigned
Component: Database layer | Version: dev
(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/36034#comment:3>

Django

unread,
Jan 2, 2025, 7:06:56 AMJan 2
to django-...@googlegroups.com
#36034: ForeignKey to CompositePrimaryKey crashes.
-------------------------------------+-------------------------------------
Reporter: Mariusz Felisiak | Owner: Mariusz
| Felisiak
Type: Bug | Status: closed
Component: Database layer | Version: dev
(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:"b322319f9d779b8726436421daae2862a380061d" b322319]:
{{{#!CommitTicketReference repository=""
revision="b322319f9d779b8726436421daae2862a380061d"
Fixed #36034 -- Added system check for
ForeignKey/ForeignObject/ManyToManyField to CompositePrimaryKeys.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/36034#comment:4>
Reply all
Reply to author
Forward
0 new messages