mirror of
https://github.com/django/django.git
synced 2024-12-22 09:05:43 +00:00
Fixed #35996 -- Fixed database serialization crash when serializing a many-to-many field that had a prefetch.
This commit is contained in:
parent
a8b70aeffd
commit
20f9f61805
@ -74,7 +74,11 @@ class Serializer(base.Serializer):
|
||||
return value.natural_key()
|
||||
|
||||
def queryset_iterator(obj, field):
|
||||
return getattr(obj, field.name).iterator()
|
||||
attr = getattr(obj, field.name)
|
||||
chunk_size = (
|
||||
2000 if getattr(attr, "prefetch_cache_name", None) else None
|
||||
)
|
||||
return attr.iterator(chunk_size)
|
||||
|
||||
else:
|
||||
|
||||
@ -82,12 +86,9 @@ class Serializer(base.Serializer):
|
||||
return self._value_from_field(value, value._meta.pk)
|
||||
|
||||
def queryset_iterator(obj, field):
|
||||
return (
|
||||
getattr(obj, field.name)
|
||||
.select_related(None)
|
||||
.only("pk")
|
||||
.iterator()
|
||||
)
|
||||
query_set = getattr(obj, field.name).select_related(None).only("pk")
|
||||
chunk_size = 2000 if query_set._prefetch_related_lookups else None
|
||||
return query_set.iterator(chunk_size=chunk_size)
|
||||
|
||||
m2m_iter = getattr(obj, "_prefetched_objects_cache", {}).get(
|
||||
field.name,
|
||||
|
@ -148,7 +148,11 @@ class Serializer(base.Serializer):
|
||||
self.xml.endElement("object")
|
||||
|
||||
def queryset_iterator(obj, field):
|
||||
return getattr(obj, field.name).iterator()
|
||||
attr = getattr(obj, field.name)
|
||||
chunk_size = (
|
||||
2000 if getattr(attr, "prefetch_cache_name", None) else None
|
||||
)
|
||||
return attr.iterator(chunk_size)
|
||||
|
||||
else:
|
||||
|
||||
@ -156,12 +160,9 @@ class Serializer(base.Serializer):
|
||||
self.xml.addQuickElement("object", attrs={"pk": str(value.pk)})
|
||||
|
||||
def queryset_iterator(obj, field):
|
||||
return (
|
||||
getattr(obj, field.name)
|
||||
.select_related(None)
|
||||
.only("pk")
|
||||
.iterator()
|
||||
)
|
||||
query_set = getattr(obj, field.name).select_related(None).only("pk")
|
||||
chunk_size = 2000 if query_set._prefetch_related_lookups else None
|
||||
return query_set.iterator(chunk_size=chunk_size)
|
||||
|
||||
m2m_iter = getattr(obj, "_prefetched_objects_cache", {}).get(
|
||||
field.name,
|
||||
|
@ -7,6 +7,7 @@ from django.core import serializers
|
||||
from django.core.serializers import SerializerDoesNotExist
|
||||
from django.core.serializers.base import ProgressBar
|
||||
from django.db import connection, transaction
|
||||
from django.db.models import Prefetch
|
||||
from django.http import HttpResponse
|
||||
from django.test import SimpleTestCase, override_settings, skipUnlessDBFeature
|
||||
from django.test.utils import Approximate
|
||||
@ -18,6 +19,7 @@ from .models import (
|
||||
AuthorProfile,
|
||||
BaseModel,
|
||||
Category,
|
||||
CategoryMetaData,
|
||||
Child,
|
||||
ComplexModel,
|
||||
Movie,
|
||||
@ -275,18 +277,45 @@ class SerializersTestBase:
|
||||
serializers.serialize(self.serializer_name, [mv])
|
||||
|
||||
def test_serialize_prefetch_related_m2m(self):
|
||||
# One query for the Article table and one for each prefetched m2m
|
||||
# field.
|
||||
with self.assertNumQueries(4):
|
||||
# One query for the Article table, one for each prefetched m2m
|
||||
# field, and one extra one for the nested prefetch for the Topics
|
||||
# that have a relationship to the Category.
|
||||
with self.assertNumQueries(5):
|
||||
serializers.serialize(
|
||||
self.serializer_name,
|
||||
Article.objects.prefetch_related("categories", "meta_data", "topics"),
|
||||
Article.objects.prefetch_related(
|
||||
"meta_data",
|
||||
"topics",
|
||||
Prefetch(
|
||||
"categories",
|
||||
queryset=Category.objects.prefetch_related("topic_set"),
|
||||
),
|
||||
),
|
||||
)
|
||||
# One query for the Article table, and three m2m queries for each
|
||||
# article.
|
||||
with self.assertNumQueries(7):
|
||||
serializers.serialize(self.serializer_name, Article.objects.all())
|
||||
|
||||
def test_serialize_prefetch_related_m2m_with_natural_keys(self):
|
||||
# One query for the Article table, one for each prefetched m2m
|
||||
# field, and a query to get the categories for each Article (two in
|
||||
# total).
|
||||
with self.assertNumQueries(5):
|
||||
serializers.serialize(
|
||||
self.serializer_name,
|
||||
Article.objects.prefetch_related(
|
||||
Prefetch(
|
||||
"meta_data",
|
||||
queryset=CategoryMetaData.objects.prefetch_related(
|
||||
"category_set"
|
||||
),
|
||||
),
|
||||
"topics",
|
||||
),
|
||||
use_natural_foreign_keys=True,
|
||||
)
|
||||
|
||||
def test_serialize_with_null_pk(self):
|
||||
"""
|
||||
Serialized data with no primary key results
|
||||
|
Loading…
Reference in New Issue
Block a user