summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Evans <mark@hellobaton.com>2022-09-03 09:53:58 -0400
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2022-09-05 20:23:32 +0200
commit19e0587ee596debf77540d6a08ccb6507e60b6a7 (patch)
treed896dcf55e3e84901dbba69c80189be7129eaef6
parent604fadde11966c5fdfe5a236a7a3963ee868f764 (diff)
Fixed #33937 -- Optimized serialization of related m2m fields without natural keys.
-rw-r--r--AUTHORS1
-rw-r--r--django/core/serializers/python.py8
-rw-r--r--django/core/serializers/xml_serializer.py8
-rw-r--r--tests/serializers/tests.py27
4 files changed, 42 insertions, 2 deletions
diff --git a/AUTHORS b/AUTHORS
index 8c2ab361d2..e3c54397ff 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -616,6 +616,7 @@ answer newbie questions, and generally made Django that much better:
Mario Gonzalez <gonzalemario@gmail.com>
Mariusz Felisiak <felisiak.mariusz@gmail.com>
Mark Biggers <biggers@utsl.com>
+ Mark Evans <mark@meltdownlabs.com>
Mark Gensler <mark.gensler@protonmail.com>
mark@junklight.com
Mark Lavin <markdlavin@gmail.com>
diff --git a/django/core/serializers/python.py b/django/core/serializers/python.py
index a3918bf9d2..fa3bce2948 100644
--- a/django/core/serializers/python.py
+++ b/django/core/serializers/python.py
@@ -70,14 +70,20 @@ class Serializer(base.Serializer):
def m2m_value(value):
return value.natural_key()
+ def queryset_iterator(obj, field):
+ return getattr(obj, field.name).iterator()
+
else:
def m2m_value(value):
return self._value_from_field(value, value._meta.pk)
+ def queryset_iterator(obj, field):
+ return getattr(obj, field.name).only("pk").iterator()
+
m2m_iter = getattr(obj, "_prefetched_objects_cache", {}).get(
field.name,
- getattr(obj, field.name).iterator(),
+ queryset_iterator(obj, field),
)
self._current[field.name] = [m2m_value(related) for related in m2m_iter]
diff --git a/django/core/serializers/xml_serializer.py b/django/core/serializers/xml_serializer.py
index 8d3918cfaa..1d3269c41a 100644
--- a/django/core/serializers/xml_serializer.py
+++ b/django/core/serializers/xml_serializer.py
@@ -146,14 +146,20 @@ class Serializer(base.Serializer):
self.xml.endElement("natural")
self.xml.endElement("object")
+ def queryset_iterator(obj, field):
+ return getattr(obj, field.name).iterator()
+
else:
def handle_m2m(value):
self.xml.addQuickElement("object", attrs={"pk": str(value.pk)})
+ def queryset_iterator(obj, field):
+ return getattr(obj, field.name).only("pk").iterator()
+
m2m_iter = getattr(obj, "_prefetched_objects_cache", {}).get(
field.name,
- getattr(obj, field.name).iterator(),
+ queryset_iterator(obj, field),
)
for relobj in m2m_iter:
handle_m2m(relobj)
diff --git a/tests/serializers/tests.py b/tests/serializers/tests.py
index 48899cb3fb..3cc937d58d 100644
--- a/tests/serializers/tests.py
+++ b/tests/serializers/tests.py
@@ -410,6 +410,33 @@ class SerializersTestBase:
self.assertEqual(self._get_field_values(child_data, "parent_m2m"), [])
self.assertEqual(self._get_field_values(child_data, "parent_data"), [])
+ def test_serialize_only_pk(self):
+ with self.assertNumQueries(5) as ctx:
+ serializers.serialize(
+ self.serializer_name,
+ Article.objects.all(),
+ use_natural_foreign_keys=False,
+ )
+
+ categories_sql = ctx[1]["sql"]
+ self.assertNotIn(connection.ops.quote_name("meta_data_id"), categories_sql)
+ meta_data_sql = ctx[2]["sql"]
+ self.assertNotIn(connection.ops.quote_name("kind"), meta_data_sql)
+
+ def test_serialize_no_only_pk_with_natural_keys(self):
+ with self.assertNumQueries(5) as ctx:
+ serializers.serialize(
+ self.serializer_name,
+ Article.objects.all(),
+ use_natural_foreign_keys=True,
+ )
+
+ categories_sql = ctx[1]["sql"]
+ self.assertNotIn(connection.ops.quote_name("meta_data_id"), categories_sql)
+ # CategoryMetaData has natural_key().
+ meta_data_sql = ctx[2]["sql"]
+ self.assertIn(connection.ops.quote_name("kind"), meta_data_sql)
+
class SerializerAPITests(SimpleTestCase):
def test_stream_class(self):