Commit ca7b1f6d by Tom Christie

Optimizations play nicely with select_related, prefetch_related

parent 720a37d3
......@@ -101,17 +101,7 @@ class RelatedField(Field):
def get_iterable(self, instance, source_attrs):
relationship = get_attribute(instance, source_attrs)
relationship = relationship.all() if (hasattr(relationship, 'all')) else relationship
if self.use_pk_only_optimization():
# Optimized case, return mock objects only containing the pk attribute.
return [
PKOnlyObject(pk=pk)
for pk in relationship.values_list('pk', flat=True)
]
# Standard case, return the object instances.
return relationship
return relationship.all() if (hasattr(relationship, 'all')) else relationship
@property
def choices(self):
......
......@@ -92,6 +92,12 @@ class HyperlinkedManyToManyTests(TestCase):
with self.assertNumQueries(4):
self.assertEqual(serializer.data, expected)
def test_many_to_many_retrieve_prefetch_related(self):
queryset = ManyToManySource.objects.all().prefetch_related('targets')
serializer = ManyToManySourceSerializer(queryset, many=True, context={'request': request})
with self.assertNumQueries(2):
serializer.data
def test_reverse_many_to_many_retrieve(self):
queryset = ManyToManyTarget.objects.all()
serializer = ManyToManyTargetSerializer(queryset, many=True, context={'request': request})
......
......@@ -71,6 +71,12 @@ class PKManyToManyTests(TestCase):
with self.assertNumQueries(4):
self.assertEqual(serializer.data, expected)
def test_many_to_many_retrieve_prefetch_related(self):
queryset = ManyToManySource.objects.all().prefetch_related('targets')
serializer = ManyToManySourceSerializer(queryset, many=True)
with self.assertNumQueries(2):
serializer.data
def test_reverse_many_to_many_retrieve(self):
queryset = ManyToManyTarget.objects.all()
serializer = ManyToManyTargetSerializer(queryset, many=True)
......@@ -188,6 +194,12 @@ class PKForeignKeyTests(TestCase):
with self.assertNumQueries(3):
self.assertEqual(serializer.data, expected)
def test_reverse_foreign_key_retrieve_prefetch_related(self):
queryset = ForeignKeyTarget.objects.all().prefetch_related('sources')
serializer = ForeignKeyTargetSerializer(queryset, many=True)
with self.assertNumQueries(2):
serializer.data
def test_foreign_key_update(self):
data = {'id': 1, 'name': 'source-1', 'target': 2}
instance = ForeignKeySource.objects.get(pk=1)
......
......@@ -54,7 +54,14 @@ class SlugForeignKeyTests(TestCase):
{'id': 2, 'name': 'source-2', 'target': 'target-1'},
{'id': 3, 'name': 'source-3', 'target': 'target-1'}
]
self.assertEqual(serializer.data, expected)
with self.assertNumQueries(4):
self.assertEqual(serializer.data, expected)
def test_foreign_key_retrieve_select_related(self):
queryset = ForeignKeySource.objects.all().select_related('target')
serializer = ForeignKeySourceSerializer(queryset, many=True)
with self.assertNumQueries(1):
serializer.data
def test_reverse_foreign_key_retrieve(self):
queryset = ForeignKeyTarget.objects.all()
......@@ -65,6 +72,12 @@ class SlugForeignKeyTests(TestCase):
]
self.assertEqual(serializer.data, expected)
def test_reverse_foreign_key_retrieve_prefetch_related(self):
queryset = ForeignKeyTarget.objects.all().prefetch_related('sources')
serializer = ForeignKeyTargetSerializer(queryset, many=True)
with self.assertNumQueries(2):
serializer.data
def test_foreign_key_update(self):
data = {'id': 1, 'name': 'source-1', 'target': 'target-2'}
instance = ForeignKeySource.objects.get(pk=1)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment