Fixed #33937 -- Optimized serialization of related m2m fields without natural keys.
This commit is contained in:
parent
604fadde11
commit
19e0587ee5
1
AUTHORS
1
AUTHORS
|
@ -616,6 +616,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Mario Gonzalez <gonzalemario@gmail.com>
|
Mario Gonzalez <gonzalemario@gmail.com>
|
||||||
Mariusz Felisiak <felisiak.mariusz@gmail.com>
|
Mariusz Felisiak <felisiak.mariusz@gmail.com>
|
||||||
Mark Biggers <biggers@utsl.com>
|
Mark Biggers <biggers@utsl.com>
|
||||||
|
Mark Evans <mark@meltdownlabs.com>
|
||||||
Mark Gensler <mark.gensler@protonmail.com>
|
Mark Gensler <mark.gensler@protonmail.com>
|
||||||
mark@junklight.com
|
mark@junklight.com
|
||||||
Mark Lavin <markdlavin@gmail.com>
|
Mark Lavin <markdlavin@gmail.com>
|
||||||
|
|
|
@ -70,14 +70,20 @@ class Serializer(base.Serializer):
|
||||||
def m2m_value(value):
|
def m2m_value(value):
|
||||||
return value.natural_key()
|
return value.natural_key()
|
||||||
|
|
||||||
|
def queryset_iterator(obj, field):
|
||||||
|
return getattr(obj, field.name).iterator()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
def m2m_value(value):
|
def m2m_value(value):
|
||||||
return self._value_from_field(value, value._meta.pk)
|
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(
|
m2m_iter = getattr(obj, "_prefetched_objects_cache", {}).get(
|
||||||
field.name,
|
field.name,
|
||||||
getattr(obj, field.name).iterator(),
|
queryset_iterator(obj, field),
|
||||||
)
|
)
|
||||||
self._current[field.name] = [m2m_value(related) for related in m2m_iter]
|
self._current[field.name] = [m2m_value(related) for related in m2m_iter]
|
||||||
|
|
||||||
|
|
|
@ -146,14 +146,20 @@ class Serializer(base.Serializer):
|
||||||
self.xml.endElement("natural")
|
self.xml.endElement("natural")
|
||||||
self.xml.endElement("object")
|
self.xml.endElement("object")
|
||||||
|
|
||||||
|
def queryset_iterator(obj, field):
|
||||||
|
return getattr(obj, field.name).iterator()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
def handle_m2m(value):
|
def handle_m2m(value):
|
||||||
self.xml.addQuickElement("object", attrs={"pk": str(value.pk)})
|
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(
|
m2m_iter = getattr(obj, "_prefetched_objects_cache", {}).get(
|
||||||
field.name,
|
field.name,
|
||||||
getattr(obj, field.name).iterator(),
|
queryset_iterator(obj, field),
|
||||||
)
|
)
|
||||||
for relobj in m2m_iter:
|
for relobj in m2m_iter:
|
||||||
handle_m2m(relobj)
|
handle_m2m(relobj)
|
||||||
|
|
|
@ -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_m2m"), [])
|
||||||
self.assertEqual(self._get_field_values(child_data, "parent_data"), [])
|
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):
|
class SerializerAPITests(SimpleTestCase):
|
||||||
def test_stream_class(self):
|
def test_stream_class(self):
|
||||||
|
|
Loading…
Reference in New Issue