Optimizations play nicely with select_related, prefetch_related

This commit is contained in:
Tom Christie 2014-12-10 21:09:45 +00:00
parent 720a37d3de
commit ca7b1f6d51
4 changed files with 33 additions and 12 deletions

View File

@ -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):

View File

@ -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})

View File

@ -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)

View File

@ -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)