From 6fcbbe0b855d8701a4da1b65772ccf326f996b9e Mon Sep 17 00:00:00 2001 From: Natalia <124304+nessita@users.noreply.github.com> Date: Fri, 24 Oct 2025 09:50:01 -0300 Subject: [PATCH 1/2] Fixed IntegrityError in bulk_create.tests.BulkCreateTransactionTests due to duplicate primary keys. Some tests in BulkCreateTransactionTests were inserting Country objects with hardcoded primary keys, which could conflict with existing rows (if the sequence value wasn't bumped by another test). Updated the tests to dynamically select an unused primary key instead. Thanks to Simon Charette for the exhaustive and enlightening review. --- tests/bulk_create/tests.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/bulk_create/tests.py b/tests/bulk_create/tests.py index 8ab918fff57d..7b77ffed3d0c 100644 --- a/tests/bulk_create/tests.py +++ b/tests/bulk_create/tests.py @@ -889,19 +889,27 @@ def test_db_default_primary_key(self): class BulkCreateTransactionTests(TransactionTestCase): available_apps = ["bulk_create"] + def get_unused_country_id(self): + # Find a serial ID that hasn't been used already and has enough of a + # buffer for the following `bulk_create` call without an explicit pk + # not to conflict. + return getattr(Country.objects.last(), "id", 10) + 100 + def test_no_unnecessary_transaction(self): + unused_id = self.get_unused_country_id() with self.assertNumQueries(1): Country.objects.bulk_create( - [Country(id=1, name="France", iso_two_letter="FR")] + [Country(id=unused_id, name="France", iso_two_letter="FR")] ) with self.assertNumQueries(1): Country.objects.bulk_create([Country(name="Canada", iso_two_letter="CA")]) def test_objs_with_and_without_pk(self): + unused_id = self.get_unused_country_id() with self.assertNumQueries(4): Country.objects.bulk_create( [ - Country(id=10, name="France", iso_two_letter="FR"), + Country(id=unused_id, name="France", iso_two_letter="FR"), Country(name="Canada", iso_two_letter="CA"), ] ) From 3ff32c50d143d8a498f9a5dfef1a31b16a7456fe Mon Sep 17 00:00:00 2001 From: Ken Nzioka Date: Wed, 22 Oct 2025 10:48:23 +0300 Subject: [PATCH 2/2] Fixed #36674 -- Fixed memory leak in select_related(). --- django/db/models/sql/compiler.py | 17 ++++++++--------- tests/select_related/tests.py | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index 0e483dc4f649..14603d57733e 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -228,6 +228,13 @@ def collapse_group_by(self, expressions, having): ] return expressions + @classmethod + def get_select_from_parent(cls, klass_info): + for ki in klass_info["related_klass_infos"]: + if ki["from_parent"]: + ki["select_fields"] = klass_info["select_fields"] + ki["select_fields"] + cls.get_select_from_parent(ki) + def get_select(self, with_col_aliases=False): """ Return three values: @@ -300,15 +307,7 @@ def get_select(self, with_col_aliases=False): related_klass_infos = self.get_related_selections(select, select_mask) klass_info["related_klass_infos"] = related_klass_infos - def get_select_from_parent(klass_info): - for ki in klass_info["related_klass_infos"]: - if ki["from_parent"]: - ki["select_fields"] = ( - klass_info["select_fields"] + ki["select_fields"] - ) - get_select_from_parent(ki) - - get_select_from_parent(klass_info) + self.get_select_from_parent(klass_info) ret = [] col_idx = 1 diff --git a/tests/select_related/tests.py b/tests/select_related/tests.py index 41ed350cf3da..59d1270aa069 100644 --- a/tests/select_related/tests.py +++ b/tests/select_related/tests.py @@ -1,6 +1,9 @@ +import gc + from django.core.exceptions import FieldError from django.db.models import FETCH_PEERS from django.test import SimpleTestCase, TestCase +from django.test.utils import garbage_collect from .models import ( Bookmark, @@ -57,6 +60,17 @@ def setUpTestData(cls): "Amanita muscaria" ) + def setup_gc_debug(self): + self.addCleanup(gc.set_debug, 0) + self.addCleanup(gc.enable) + gc.disable() + garbage_collect() + gc.set_debug(gc.DEBUG_SAVEALL) + + def assert_no_memory_leaks(self): + garbage_collect() + self.assertEqual(gc.garbage, []) + def test_access_fks_without_select_related(self): """ Normally, accessing FKs doesn't fill in related objects @@ -128,6 +142,11 @@ def test_select_related_with_extra(self): ) self.assertEqual(s.id + 10, s.a) + def test_select_related_memory_leak(self): + self.setup_gc_debug() + list(Species.objects.select_related("genus")) + self.assert_no_memory_leaks() + def test_certain_fields(self): """ The optional fields passed to select_related() control which related