summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Johnson <me@adamj.eu>2025-09-05 11:04:27 +0100
committerJacob Walls <jacobtylerwalls@gmail.com>2025-10-16 14:52:22 -0400
commita321d961b03d47b7f0c2e21a2370fc9e74c1889b (patch)
treeb57a131d63215b60f0c6fbfd8cb5f3e35fcff6e9
parente097e8a12f21a4e92594830f1ad1942b31916d0f (diff)
Refs #28586 -- Made fetch modes pickle as singletons.
This change ensures that we don’t create new instances of fetch modes when pickling and unpickling, saving memory and preserving their singleton nature.
-rw-r--r--django/db/models/fetch_modes.py9
-rw-r--r--tests/queryset_pickle/tests.py23
2 files changed, 32 insertions, 0 deletions
diff --git a/django/db/models/fetch_modes.py b/django/db/models/fetch_modes.py
index a22ccd8a23..2b5e6aa212 100644
--- a/django/db/models/fetch_modes.py
+++ b/django/db/models/fetch_modes.py
@@ -16,6 +16,9 @@ class FetchOne(FetchMode):
def fetch(self, fetcher, instance):
fetcher.fetch_one(instance)
+ def __reduce__(self):
+ return "FETCH_ONE"
+
FETCH_ONE = FetchOne()
@@ -36,6 +39,9 @@ class FetchPeers(FetchMode):
else:
fetcher.fetch_one(instance)
+ def __reduce__(self):
+ return "FETCH_PEERS"
+
FETCH_PEERS = FetchPeers()
@@ -48,5 +54,8 @@ class Raise(FetchMode):
field_name = fetcher.field.name
raise FieldFetchBlocked(f"Fetching of {klass}.{field_name} blocked.") from None
+ def __reduce__(self):
+ return "RAISE"
+
RAISE = Raise()
diff --git a/tests/queryset_pickle/tests.py b/tests/queryset_pickle/tests.py
index acdb582a0a..074a8ed550 100644
--- a/tests/queryset_pickle/tests.py
+++ b/tests/queryset_pickle/tests.py
@@ -351,6 +351,29 @@ class PickleabilityTestCase(TestCase):
event.edition_set.create()
self.assert_pickles(event.edition_set.order_by("event"))
+ def test_fetch_mode_fetch_one(self):
+ restored = pickle.loads(pickle.dumps(self.happening))
+ self.assertIs(restored._state.fetch_mode, models.FETCH_ONE)
+
+ def test_fetch_mode_fetch_peers(self):
+ Happening.objects.create()
+ objs = list(Happening.objects.fetch_mode(models.FETCH_PEERS))
+ self.assertEqual(objs[0]._state.fetch_mode, models.FETCH_PEERS)
+ self.assertEqual(len(objs[0]._state.peers), 2)
+
+ restored = pickle.loads(pickle.dumps(objs))
+
+ self.assertIs(restored[0]._state.fetch_mode, models.FETCH_PEERS)
+ # Peers not restored because weak references are not picklable.
+ self.assertEqual(restored[0]._state.peers, ())
+
+ def test_fetch_mode_raise(self):
+ objs = list(Happening.objects.fetch_mode(models.RAISE))
+ self.assertEqual(objs[0]._state.fetch_mode, models.RAISE)
+
+ restored = pickle.loads(pickle.dumps(objs))
+ self.assertIs(restored[0]._state.fetch_mode, models.RAISE)
+
class InLookupTests(TestCase):
@classmethod