#32244: ORM inefficiency: ModelFormSet executes a single-object SELECT query per
formset instance when saving/validating
-------------------------------------+-------------------------------------
Reporter: Lushen Wu | Owner: nobody
Type: | Status: closed
Cleanup/optimization |
Component: Database layer | Version: 3.1
(models, ORM) |
Severity: Normal | Resolution: wontfix
Keywords: formsets | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Lushen Wu):
Thanks for taking a look! I understand that the issue is probably not a
performance bottle neck in most projects, but if it truly is an extra SQL
query translating to millions of unnecessary roundtrips across all Django
deployments (and the fix would be relatively straightforward), I feel like
it still deserves some consideration. I'd be willing to contribute to a
patch if helpful.
Conceptually I'm not exactly sure why ModelChoiceField needs a Python
representation of the value to validate. I understand why this would be
needed for e.g. a CharField with a max_length requirement. But if the
ModelChoiceField value passed from the form is a PK, can it be validated
without loading the entire instance into memory? (If fetching the full
Python object is required for custom validators, the to_python() call and
SELECT query could be deferred until such a case is encountered.)
Currently the validation callstack goes BaseForm.full_clean() ->
BaseForm._clean_fields(value) -> Field.clean(value) ->
ModelChoiceField.to_python(value).
From what I can see, ModelChoiceField does not override Field.validate()
or Field.run_validators(). So the only validation step performed by
ModelChoiceField basically checks whether the Book instance generated by
Field.to_python() belongs to ModelChoiceField._get_choices() <-- which by
default is a ModelChoiceIterator for all Book objects.
Is there a "lighter" way of doing this that simply checks whether the
ModelChoiceField value (as a PK) exists in the corresponding model table?
If the SELECT query is simply a side effect of ModelChoiceField inheriting
Field.clean(), then I think it would be cleaner design to have
ModelChoiceField.clean() override Field.clean() and avoid calling
to_python() in the default validation loop. And as mentioned fetch the
object only if needed for custom validators.
Thanks again!
------------------------------
P.S. The kw_args workaround you suggested seems to be the cleanest in the
meantime if this stays a wontfix.
--
Ticket URL: <https://code.djangoproject.com/ticket/32244#comment:8>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/066.f3fa61785bcea64af4b465bab9597192%40djangoproject.com.