Commit e44ab5bb authored by Anton I. Sipos's avatar Anton I. Sipos
Browse files

Fixed #18949 -- Improve performance of model_to_dict with many-to-many

When calling model_to_dict, improve performance of the generated SQL by
using values_list to determine primary keys of many to many objects. Add
a specific test for this function, test_model_to_dict_many_to_many

Thanks to brian for the original report and suggested fix.
parent 8d3f932f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -126,7 +126,7 @@ def model_to_dict(instance, fields=None, exclude=None):
                data[f.name] = []
            else:
                # MultipleChoiceWidget needs a list of pks, not object instances.
                data[f.name] = [obj.pk for obj in f.value_from_object(instance)]
                data[f.name] = list(f.value_from_object(instance).values_list('pk', flat=True))
        else:
            data[f.name] = f.value_from_object(instance)
    return data
+36 −0
Original line number Diff line number Diff line
@@ -561,6 +561,42 @@ class UniqueTest(TestCase):
            "slug": "Django 1.0"}, instance=p)
        self.assertTrue(form.is_valid())

class ModelToDictTests(TestCase):
    """
    Tests for forms.models.model_to_dict
    """
    def test_model_to_dict_many_to_many(self):
        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.save()

        with self.assertNumQueries(1):
            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):
    def test_base_form(self):
        self.assertEqual(Category.objects.count(), 0)