Kaydet (Commit) 539e3693 authored tarafından Jim Bailey's avatar Jim Bailey Kaydeden (comit) Anssi Kääriäinen

Fixed #20849 -- ModelForms do not work well with prefetch_related.

model_to_dict() (used when rendering forms) queries the database
to get the list of primary keys for ManyToMany fields. This is
unnecessary if the field queryset has been prefetched, all the
keys are already in memory and can be obtained with a simple
iteration.
üst 4202d9cf
...@@ -134,7 +134,11 @@ def model_to_dict(instance, fields=None, exclude=None): ...@@ -134,7 +134,11 @@ def model_to_dict(instance, fields=None, exclude=None):
data[f.name] = [] data[f.name] = []
else: else:
# MultipleChoiceWidget needs a list of pks, not object instances. # MultipleChoiceWidget needs a list of pks, not object instances.
data[f.name] = list(f.value_from_object(instance).values_list('pk', flat=True)) qs = f.value_from_object(instance)
if qs._result_cache is not None:
data[f.name] = [item.pk for item in qs]
else:
data[f.name] = list(qs.values_list('pk', flat=True))
else: else:
data[f.name] = f.value_from_object(instance) data[f.name] = f.value_from_object(instance)
return data return data
......
...@@ -824,6 +824,41 @@ class ModelToDictTests(TestCase): ...@@ -824,6 +824,41 @@ class ModelToDictTests(TestCase):
# Ensure many-to-many relation appears as a list # Ensure many-to-many relation appears as a list
self.assertIsInstance(d['categories'], list) self.assertIsInstance(d['categories'], list)
def test_reuse_prefetched(self):
# model_to_dict should not hit the database if it can reuse
# the data populated by prefetch_related.
categories = [
Category(name='TestName1', slug='TestName1', url='url1'),
Category(name='TestName2', slug='TestName2', url='url2'),
Category(name='TestName3', slug='TestName3', url='url3')
]
for c in categories:
c.save()
writer = Writer(name='Test writer')
writer.save()
art = Article(
headline='Test article',
slug='test-article',
pub_date=datetime.date(1988, 1, 4),
writer=writer,
article='Hello.'
)
art.save()
for c in categories:
art.categories.add(c)
art = Article.objects.prefetch_related('categories').get(pk=art.pk)
with self.assertNumQueries(0):
d = model_to_dict(art)
#Ensure all many-to-many categories appear in model_to_dict
for c in categories:
self.assertIn(c.pk, d['categories'])
#Ensure many-to-many relation appears as a list
self.assertIsInstance(d['categories'], list)
class OldFormForXTests(TestCase): class OldFormForXTests(TestCase):
def test_base_form(self): def test_base_form(self):
self.assertEqual(Category.objects.count(), 0) self.assertEqual(Category.objects.count(), 0)
......
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