Opened 13 years ago
Last modified 20 months ago
#18597 assigned Cleanup/optimization
`BaseInlineFormSet` should attempt to get it's queryset from it's instance related manager before falling back to it's model's default manager — at Initial Version
| Reported by: | Simon Charette | Owned by: | nobody |
|---|---|---|---|
| Component: | Forms | Version: | dev |
| Severity: | Normal | Keywords: | model formset inline |
| Cc: | hugo@…, Florian Demmer | Triage Stage: | Accepted |
| Has patch: | yes | Needs documentation: | yes |
| Needs tests: | no | Patch needs improvement: | yes |
| Easy pickings: | no | UI/UX: | no |
Description
The newly introduced prefetch_related method can be quite handy to avoid unnecessary queries (thanks Luke :), however it's quite useless when used with BaseInlineFormSet since it won't even try to get its needed `queryset` from the related manager.
i.e.
from django.db import models class Author(models.Model): name = models.CharField(max_length=255) class Book(models.Model): name = models.CharField(max_length=255) author = models.ForeignKey(Author, related_name='books') class Meta: # Needed because `BaseModelFormSet.get_query_set` wants an ordered set or issue another query ordering = ('pk',)
In [1]: from django.conf import settings
In [2]: from django.db import connection
In [3]: from library.models import *
In [4]: from django.forms.models import inlineformset_factory
In [5]: a = Author.objects.create(name='David Abram')
In [6]: b1 = Book.objects.create(name='Becoming Animal', author=a)
In [7]: b2 = Book.objects.create(name='The Spell of the Sensuous', author=a)
In [8]: BookInlineFormSet = inlineformset_factory(Author, Book)
In [9]: settings.DEBUG = True
In [10]: instance = Author.objects.prefetch_related('books').get()
In [11]: BookInlineFormSet(instance=instance)
Out[11]: <django.forms.formsets.BookFormFormSet at 0x3c68d50>
In [12]: print connection.queries
[{u'time': u'0.000', u'sql': u'SELECT "library_author"."id", "library_author"."name" FROM "library_author"'}, {u'time': u'0.000', u'sql': u'SELECT "library_book"."id", "library_book"."name", "library_book"."author_id" FROM "library_book" WHERE "library_book"."author_id" IN (1) ORDER BY "library_book"."id" ASC'},
{u'time': u'0.000', u'sql': u'SELECT "library_book"."id", "library_book"."name", "library_book"."author_id" FROM "library_book" WHERE "library_book"."author_id" = 1 ORDER BY "library_book"."id" ASC'}]
I guess it's only a matter of time before people start trying to optimize their formsets (or their ModelAdmin by overriding get_queryset) and stumble on this limitation.
I've written a patch (I'll create a pull request) for which I'll write tests if this optimization is Accepted.
ticket-18597.0.diff